JDBC学习笔记——增删改查

1、数据库准备 

要用JDBC操作数据库,第一步当然是建立数据表:

?


1

2

3

4

5

6

CREATE TABLE `user` (

  `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,

  `name` varchar(45) DEFAULT NULL,

  `birthday` date DEFAULT NULL,

  `money` double DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2、JDBC连接数据库的基本步骤                                                            

JDBC连接数据库包含以下几个基本步骤:1、注册驱动 ;2、建立连接(Connection);3、创建SQL语句(Statement);4、执行语句;5、处理执行结果(ResultSet);6、释放资源。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

public static void test() throws SQLException{

    // 1.注册驱动

    Class.forName("com.mysql.jdbc.Driver");

    // 2.建立连接  url格式 - JDBC:子协议:子名称//主机名:端口/数据库名?属性名=属性值&…

    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "");

    // 3.创建语句

    Statement st = conn.createStatement();

    // 4.执行语句

    ResultSet rs = st.executeQuery("select * from user");

    // 5.处理结果

    while (rs.next()) {

          System.out.println(rs.getObject(1) + "\t" + rs.getObject(2) + "\t" + rs.getObject(3) + "\t" + rs.getObject(4));

    }

    // 6.释放资源

    rs.close();

    st.close();

    conn.close();

}

3、简单的增删改查  

第二节的代码有一个问题,如果我们在执行代码时抛出异常,那么Connection就无法关闭了,所以我们应该把关闭资源操作放入finally中,这样就无论如何都会关闭这些数据库连接资源。同时我们还会扩展程序功能,上面的例子只是展示了一个查询操作,接下来将会展示最常用的增、删、改、查四个操作。首先介绍一个JdbcUtils类,该类会封装数据库连接步骤中的第一步、第二步及第六步操作,分别是注册驱动,建立连接及释放资源操作。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

public final class JdbcUtils {

    static {

        try {

            Class.forName("com.mysql.jdbc.Driver");

        } catch (ClassNotFoundException e) {

            throw new ExceptionInInitializerError(e);

        }

    }

   

    private JdbcUtils() {

    }

    public static Connection getConnection() throws SQLException {

        return DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "");

    }

    public static void free(ResultSet rs, Statement st, Connection conn) {

        try {

            if (rs != null)

                rs.close();

        } catch (SQLException e) {

            e.printStackTrace();

        } finally {

            try {

                if (st != null)

                    st.close();

            } catch (SQLException e) {

                e.printStackTrace();

            } finally {

                if (conn != null)

                    try {

                        conn.close();

                    } catch (SQLException e) {

                        e.printStackTrace();

                    }

            }

        }

    }

}

  可以看到,这个类的构造函数是一个私有构造函数,所以我们将无法创建这个类的实例。在静态初始化域,我们进行了注册驱动操作,静态初始化域只会在类加载的时候执行一次,这样可以保证只要加载了这个类,我们会且仅会注册一次驱动。然后getConnection()方法封装了建立连接操作,free(rs, st, conn)方法封装了释放资源操作。接下来可以看看如何使用JdbcUtils类进行增、删、改、查操作:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

//增加操作

void create() throws SQLException {

    Connection conn = null;

    Statement st = null;

    ResultSet rs = null;

    try {

       

        conn = JdbcUtils.getConnection();

        st = conn.createStatement();

        int i = st

                .executeUpdate("insert into user(name,birthday, money) values (‘name1‘, ‘1987-01-01‘, 400) ");

        System.out.println("i=" + i);

    } finally {

        JdbcUtils.free(rs, st, conn);

    }

}

//删除操作

void delete() throws SQLException {

    Connection conn = null;

    Statement st = null;

    ResultSet rs = null;

    try {

        conn = JdbcUtils.getConnection();

        st = conn.createStatement();

        int i = st.executeUpdate("delete from user where id>4");

        System.out.println("i=" + i);

    } finally {

        JdbcUtils.free(rs, st, conn);

    }

}

//修改操作

void update() throws SQLException {

    Connection conn = null;

    Statement st = null;

    ResultSet rs = null;

    try {

        conn = JdbcUtils.getConnection();

        st = conn.createStatement();

        int i = st.executeUpdate("update user set money=money+10 ");

        System.out.println("i=" + i);

    } finally {

        JdbcUtils.free(rs, st, conn);

    }

}

//查询操作

void read() throws SQLException {

    Connection conn = null;

    Statement st = null;

    ResultSet rs = null;

    try {

        conn = JdbcUtils.getConnection();

        st = conn.createStatement();

        rs = st.executeQuery("select id, name, money, birthday  from user");

        while (rs.next()) {

            System.out.println(rs.getObject("id") + "\t"

                    + rs.getObject("name") + "\t"

                    + rs.getObject("birthday") + "\t"

                    + rs.getObject("money"));

        }

    } finally {

        JdbcUtils.free(rs, st, conn);

    }

}  

4、面向对象封装增删改查                                                               

第三节的例子只是为了展示如何使用JDBC进行增删改查操作,在项目中真正使用时,我们是不会像上面的例子这样简单使用的,Java是面向对象的,所以我们一般会使用面向对象的思想对操作进行封装。首先,其实对于数据表每一条数据,我们都可以认为它是一个对象实例,例如此例中我们定义的数据表User有id,name,birthday和money四个属性,对应的我们可以创建User类如下:

?


1

2

3

4

5

6

7

8

public class User {

    private int id;

    private String name;

    private Date birthday;

    private float money;

     

       //getters and setters

}

  按照"面向接口编程而非面向实现编程"的原则,我们可以定义数据表操作的接口如下:

?


1

2

3

4

5

6

public interface UserDao {

    public void addUser(User user);

    public User getUser(int userId);

    public void update(User user);

    public void delete(User user);

}

然后我们使用JDBC方式实现这个接口如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

public class UserDaoJdbcImpl implements UserDao {

    public void addUser(User user) {

        Connection conn = null;

        PreparedStatement ps = null;

        ResultSet rs = null;

        try {

            conn = JdbcUtils.getConnection();

            String sql = "insert into user(name,birthday, money) values (?,?,?) ";

            ps = conn.prepareStatement(sql);

            ps.setString(1, user.getName());

            ps.setDate(2, new java.sql.Date(user.getBirthday().getTime()));

            ps.setFloat(3, user.getMoney());

            ps.executeUpdate();

        } catch (SQLException e) {

            throw new RuntimeException(e.getMessage(), e);

        } finally {

            JdbcUtils.free(rs, ps, conn);

        }

    }

    public void delete(User user) {

        Connection conn = null;

        Statement st = null;

        ResultSet rs = null;

        try {

            conn = JdbcUtils.getConnection();

            st = conn.createStatement();

            String sql = "delete from user where id=" + user.getId();

            st.executeUpdate(sql);

        } catch (SQLException e) {

            throw new RuntimeException(e.getMessage(), e);

        } finally {

            JdbcUtils.free(rs, st, conn);

        }

    }

    public User getUser(int userId) {

        Connection conn = null;

        PreparedStatement ps = null;

        ResultSet rs = null;

        User user = null;

        try {

            conn = JdbcUtils.getConnection();

            String sql = "select id, name, money, birthday  from user where id=?";

            ps = conn.prepareStatement(sql);

            ps.setInt(1, userId);

            rs = ps.executeQuery();

            while (rs.next()) {

                user = new User();

                user.setId(rs.getInt("id"));

                user.setName(rs.getString("name"));

                user.setMoney(rs.getFloat("money"));

                user.setBirthday(rs.getDate("birthday"));

            }

        } catch (SQLException e) {

            throw new RuntimeException(e.getMessage(), e);

        } finally {

            JdbcUtils.free(rs, ps, conn);

        }

        return user;

    }

    public void update(User user) {

        Connection conn = null;

        PreparedStatement ps = null;

        ResultSet rs = null;

        try {

            conn = JdbcUtils.getConnection();

            String sql = "update user set name=?, birthday=?, money=? where id=? ";

            ps = conn.prepareStatement(sql);

            ps.setString(1, user.getName());

            ps.setDate(2, new java.sql.Date(user.getBirthday().getTime()));

            ps.setFloat(3, user.getMoney());

            ps.setInt(4, user.getId());

            ps.executeUpdate();

        } catch (SQLException e) {

            throw new RuntimeException(e.getMessage(), e);

        } finally {

            JdbcUtils.free(rs, ps, conn);

        }

    }

}

  可以看到,真正核心的代码其实和第二节的代码很相像,但是按照这种风格写的代码扩展性更好,如果哪一天我们不打算使用JDBC,而改用Hibernate连接数据库,使用接口编程只需修改实现,不需要修改其他部分,大大减小了修改难度。

5、传入sql执行                                                                             

需要说明的是,上面的代码使用了PreparedStatement对象,PrepareStatement是预编译的Statement对象,它在创建的时候就会把sql的大体框架搭建起来,把一些变量用占位符表示,使用时,我们再设置这些占位符的值。PrepareStatement最大的特点是可以防止sql注入,更安全,所以再需要拼接用户输入的场景,推荐使用PrepareStatement。

第四节代码的编码风格类似Hibernate,Hibernate的很多操作都是需要传入对象的,但是这种传递对象的方式灵活性不高,例如update()方法,我们把User对象上的所有属性都更新了,但是可能我们只想更新birthday一个属性,更新其他属性有点多余,所以更好的方法应该是传入sql语句,而不是一个User对象。再仔细观察,我们发现,其实我们最终只是调用了Statement上的两个方法,分别是executeUpdate和executeQuery两个方法。所以我们可以把上面的增删改查修改为如下形式:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

public class UserDaoUtils {

    private UserDaoUtils(){

    }

   

    static User executeQuery(String sql, Object[] params) throws SQLException {

        Connection conn = null;

        PreparedStatement ps = null;

        ResultSet rs = null;

        User user = null;

        try {

            conn = JdbcUtils.getConnection();

            ps = conn.prepareStatement(sql);

            for (int i = 1; i <= params.length; i++) {

                ps.setObject(i, params[i - 1]);

            }

            rs = ps.executeQuery();

            while (rs.next()) {

                user = new User();

                user.setId(rs.getInt("id"));

                user.setBirthday(rs.getDate("birthday"));

                user.setMoney(rs.getFloat("money"));

                user.setName(rs.getString("name"));

            }

        } finally {

            JdbcUtils.free(rs, ps, conn);

        }

        return user;

    }

   

    static int executeUpdate(String sql, Object[] params) throws SQLException {

        Connection conn = null;

        PreparedStatement ps = null;

        int rs = 0;

        try {

            conn = JdbcUtils.getConnection();

            ps = conn.prepareStatement(sql);

            for (int i = 1; i <= params.length; i++) {

                ps.setObject(i, params[i - 1]);

            }

            rs = ps.executeUpdate();

        } finally {

            JdbcUtils.free(null, ps, conn);

        }

        return rs;

    }

}

public class UserDaoJdbcImpl2 implements UserDao{

    @Override

    public void addUser(User user) {

        try {

            UserDaoUtils.executeUpdate("insert into user(name,birthday, money) values (?,?,?)", new Object[]{user.getName(), user.getBirthday(), user.getMoney()});

        } catch (SQLException e) {

            e.printStackTrace();

        }

    }

    @Override

    public User getUser(int userId) {

        User user = null;

        try {

            user = UserDaoUtils.executeQuery("select id, name, money, birthday  from user where id=?", new Object[]{userId});

        } catch (SQLException e) {

            e.printStackTrace();

        }

        return user;

    }

    @Override

    public void update(User user) {

        try {

            UserDaoUtils.executeUpdate("update user set name=?, birthday=?, money=? where id=?", new Object[]{user.getName(), user.getBirthday(), user.getMoney(), user.getId()});

        } catch (SQLException e) {

            e.printStackTrace();

        }

    }

    @Override

    public void delete(User user) {

        try {

            UserDaoUtils.executeUpdate("delete from user where id=?", new Object[]{user.getId()});

        } catch (SQLException e) {

            e.printStackTrace();

        }

    }

}

  首先我们定义了一个UserDaoUtils对象,该对象包含两个方法,分别是executeQuery()和executeUpdate()方法,这两个方法均包含两个参数,分别是sql语句及sql语句的参数。然后我们定义了UserDaoJdbcImpl2类,该类使用UserDaoUtils实现了UserDao接口,相较于UserDaoJdbcImpl简化了很多。

6、利用结果集元数据封装对象                                                          

上面的UserDaoJdbcImpl2和UserDaoUtils的代码都已经很简洁了,但是有个问题,如果我们想封装其他对象的JDBC操作,那么我们将不得不重新定义一对Utils和Impl,这个其实是重复劳动,那么我们有没有什么方法可以避免这些重复劳动呢?Impl对象是必须定义的,因为我们需要实现不同的对象,如果想少定义一些对象,那么就只能不定义Utils对象。查看UserUtils的exectueQuery()和executeUpdate()方法,发现只有executeQuery()方法是与User对象耦合的,而且耦合部分只有封装结果集的部分,我们可以把这一部分代码抽象成一个接口,让调用方传入,这样就可以避免这部分耦合,所以定义接口如下:

?


1

2

3

public interface RowMapper {

    public Object mapRow(ResultSet rs) throws SQLException;

}

  然后我们修改第四节的UserDaoUtils对象如下,并重命名为MyJdbcTemplate:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

public class MyJdbcTemplate {

    private MyJdbcTemplate(){}

   

    public static Object executeQuery(String sql, Object[] args, RowMapper rowMapper) {

        Connection conn = null;

        PreparedStatement ps = null;

        ResultSet rs = null;

        try {

            conn = JdbcUtils.getConnection();

            ps = conn.prepareStatement(sql);

            for (int i = 0; i < args.length; i++)

                ps.setObject(i + 1, args[i]);

            rs = ps.executeQuery();

            Object obj = null;

            if (rs.next()) {

                obj = rowMapper.mapRow(rs);

            }

            return obj;

        } catch (SQLException e) {

            throw new RuntimeException(e.getMessage(), e);

        } finally {

            JdbcUtils.free(rs, ps, conn);

        }

    }

   

    public static int executeUpdate(String sql, Object[] params) throws SQLException {

        Connection conn = null;

        PreparedStatement ps = null;

        int rs = 0;

        try {

            conn = JdbcUtils.getConnection();

            ps = conn.prepareStatement(sql);

            for (int i = 1; i <= params.length; i++) {

                ps.setObject(i, params[i - 1]);

            }

            rs = ps.executeUpdate();

        } finally {

            JdbcUtils.free(null, ps, conn);

        }

        return rs;

    }

}

  可以看到,现在我们的executeQuery()方法已经与User对象解耦了,所以整个对象都已经与User对象解耦,是一个通用方法,我们可以使用该对象实现UserDao接口如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

public class UserDaoJdbcImpl3 implements UserDao {

    @Override

    public void addUser(User user) {

        try {

            MyJdbcTemplate.executeUpdate(

                    "insert into user(name,birthday, money) values (?,?,?)",

                    new Object[] { user.getName(), user.getBirthday(),

                            user.getMoney() });

        } catch (SQLException e) {

            e.printStackTrace();

        }

    }

    @Override

    public User getUser(int userId) {

        User user = null;

        try {

            user = (User) MyJdbcTemplate.executeQuery(

                    "select id, name, money, birthday  from user where id=?",

                    new Object[] { userId }, new RowMapper() {

                        @Override

                        public Object mapRow(ResultSet rs) throws SQLException {

                            User user = new User();

                            user.setId(rs.getInt("id"));

                            user.setName(rs.getString("name"));

                            user.setMoney(rs.getFloat("money"));

                            user.setBirthday(rs.getDate("birthday"));

                            return user;

                        }

                    });

        } catch (Exception e) {

            e.printStackTrace();

        }

        return user;

    }

    @Override

    public void update(User user) {

        try {

            MyJdbcTemplate.executeUpdate(

                    "update user set name=?, birthday=?, money=? where id=?",

                    new Object[] { user.getName(), user.getBirthday(),

                            user.getMoney(), user.getId() });

        } catch (SQLException e) {

            e.printStackTrace();

        }

    }

    @Override

    public void delete(User user) {

        try {

            MyJdbcTemplate.executeUpdate("delete from user where id=?",

                    new Object[] { user.getId() });

        } catch (SQLException e) {

            e.printStackTrace();

        }

    }

}

  UserDaoJdbcImpl3的实现与第四节UserDaoJdbcImpl2的实现十分相似,只有getUser()方法与UserDaoJdbcImpl2不同,在UserDaoJdbcImpl3总,我们不仅要传递sql语句以及sql参数,我们还需要传递RowMapper对象,该对象能够帮助我们把查询结果封装成一个User对象。

7、用配置文件实现与具体类的解耦                                                       

我们一直在讲UserDao的不同实现,但是却一直没讲如何使用这些实现,要使用这些方法首先应该创建对象,最简单的创建方法应该是像下面这样:

?


1

UserDao userDao = new UserDaoJdbcImpl();

  但是这种把实现硬编码进代码中不是很优雅,如果我们想修改实现,就必须重新编译代码,更好的我们使用配置文件定义实现类,创建时读取配置文件决定应该使用哪个实现。配置文件的格式使用Java Properties格式,配置文件的内容如下:

?


1

userDaoClass=cn.test.UserDaoJdbcImpl3

  我们将使用工厂模式创建一个DaoFactory对象,该对象有一个createUserDao()方法,该方法将读返回一个UserDao接口的实现,方法的实现,我们可以选择每次都创建一个全新的返回,也可以选择第一次创建然后,缓存起来,之后就直接返回缓存对象的方法,在这里我们选择第二种,该对象的实现如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

public class DaoFactory {

    private static UserDao userDao = null;

    private static DaoFactory instance = new DaoFactory();

    private DaoFactory() {

    }

    public static DaoFactory getInstance() {

        return instance;

    }

    public UserDao createUserDao() {

        if (userDao == null) {

            try {

                Properties prop = new Properties();

                InputStream inStream = DaoFactory.class.getClassLoader()

                        .getResourceAsStream("daoconfig.properties");

                prop.load(inStream);

                String userDaoClass = prop.getProperty("userDaoClass");

                Class<?> clazz = Class.forName(userDaoClass);

                userDao = (UserDao) clazz.newInstance();

            } catch (Throwable e) {

                throw new ExceptionInInitializerError(e);

            }

        }

        return userDao;

    }

}

  最后,编写一个UserDaoTest类,对上面代码进行简单测试:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class UserDaoTest {

    public static void main(String[] args) {

        UserDao userDao = DaoFactory.getInstance().createUserDao();

       

        User user = new User();

        user.setBirthday(new Date());

        user.setMoney(234242);

        user.setName("xxxx");

        userDao.addUser(user);

       

        User u = userDao.getUser(1);

        System.out.println(u.getId() + "\t" + u.getName() + "\t" + u.getMoney() + "\t" + u.getBirthday());

    }

}

时间: 2024-07-30 12:27:20

JDBC学习笔记——增删改查的相关文章

Android学习--------实现增删改查数据库操作以及实现类似微信好友对话管理操作

最近的一个实验用到东西挺多,特地总结一下. 要求功能: 1.第一个页面添加歌曲名和歌手,跳到第二个页面列表显示所有记录,使用sqlite数据库 2.对于第二个页面显示的信息可以进行删除和修改操作,并自动刷新 最后我做的效果: 长按列表项弹出单个管理的菜单,像微信好友对话管理一样. 删除时可以直接删除这一条并在列表中直接显示,更新时弹出对话框更新内容提交后在列表中重新显示. 做此例遇到的困难: 1.菜单获取上下文 2.获取对话框中的内容 3.对话框按钮添加监听事件-----注意包不要导错:impo

eclipse控制台下实现jdbc简单的增删改查测试

1.现在MySQL中创建一个表 2.首先创建一个类 //导入的包 import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet; public class DBTil { } 3.然后实例化各个对象 1 //username和password是连接数据库的用户名和密码 2 private static String usern

zookeeper curator学习(增删改查)(1)

主要参考的是curator,github地址:https://github.com/apache/curator/tree/master/curator-examples. zookeeper版本为zookeeper-3.4.9(需要查找合适的curator版本) 源码地址:https://gitee.com/zhangjunqing/spring-boot/tree/master/zookeeper (1)pom文件如下 <project xmlns="http://maven.apac

mongoose学习笔记2--增删改查1

查询 之前我们的集合已经创建成功,我们就先来进行第一步操作 —— 查询. 查询分很多种类型,如条件查询,过滤查询等等,今天只学习了最基本的find查询. 举例: 1.find查询: obj.find(查询条件,callback); Model.find({},function(error,docs){ //若没有向find传递参数,默认的是显示所有文档 }); Model.find({ "age": 28 }, function (error, docs) { if(error){ c

JSP + Servlet + JDBC + Mysql 实现增删改查 课程管理系统

1.项目目录结构 2.项目环境 Eclipse IDE  MYSQL  jdk tomcat jar包 3.数据库相关配置 先创建一个course的数据库名,然后在建立一个course的表 要注意将id字段 自动递增 4.源代码 1.Course.java package com.hjf.entity; public class Course { private int id; private String name; private String teacher; private String

JDBC编程 之 增删改查

JDBC编程之数据增加,更改,查询,删除 1 package com.good.jdbc; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.ResultSet; 6 import java.sql.Statement; 7 8 public class Main { 9 //1数据库连接的方法就独立出来了 10 public static Connection getConnec

Hibernate学习-------数据库增删改查操作(部分)

(1)增加和删除 <span style="white-space:pre"> </span>@Test public void test() { EStudent student=new EStudent(); student.setName("张三"); student.setSex("男"); Session session=sf.openSession(); session.beginTransaction();

JAVA JDBC 简单的增删改查

package jdbc_util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class JdbcDemo { // 设置汉字编码 String jdbcUrl = "jdbc:mysql://localhost:3306/test?use

二、Django学习之增删改查

增加数据 第一种方式 def index(request): #创建记录方式1 #实例化要添加的记录(对象) student_obj = models.Student( name='dazhuang', age=23, ) #自动刷新并存储到数据库 student_obj.save() return render(request,'index.html') 第二种方式 常用方法 def index(request): #创建记录方式2 # new_obj为返回值,返回这个类的对象 (model对