0. 参考资料

点击查看【bilibili】
韩顺平_循序渐进学Java零基础【完整笔记】.pdf

1.概述

  • JDBC为访问不同的数据库提供了统一的接口, 为使用者屏蔽了细节问题
  • Java程序员使用JDBC, 可以连接任何提供了JDBC驱动的数据库, 从而完成CRUD操作

图片.png
图片.png

图片.png

实现原理

QQ图片20210916201236.jpg

2.快速入门

基本步骤

点击查看【processon】

注册驱动&获取连接

image.png

注册驱动获取连接的五种方式

  1. - 代码
  1. public class TestGetConnection {
  2. static String url = "jdbc:mysql://localhost:3306/myjdbc";
  3. static String userKey = "user";
  4. static String userValue = "root";
  5. static String passwordKey = "password";
  6. static String passwordValue = "0000";
  7. static String driverClassName = "com.mysql.jdbc.Driver";
  8. static Properties properties = new Properties();
  9. static {
  10. properties.setProperty(userKey, userValue);
  11. properties.setProperty(passwordKey, passwordValue);
  12. }
  13. @Test
  14. public void test1() throws SQLException {
  15. //1.注册驱动-创建driver对象
  16. Driver driver = new Driver();
  17. //2.获取连接-将用户名和密码放入到Properties 对象, 并作入参
  18. Connection connect = driver.connect(url, properties);
  19. System.out.println(connect);
  20. }
  21. /**
  22. * @description: 使用反射加载Driver类 ,
  23. * 动态加载,更加的灵活,减少依赖性
  24. */
  25. @Test
  26. public void test2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
  27. Class<?> aClass = Class.forName(driverClassName);
  28. Driver driver = (Driver) aClass.newInstance();
  29. Connection connect = driver.connect(url, properties);
  30. System.out.println(connect);
  31. }
  32. /**
  33. * @description: 使用DriverManager注册Driver,
  34. * 以替代 Driver 进行统一管理
  35. */
  36. @Test
  37. public void test3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
  38. Class<?> aClass = Class.forName(driverClassName);
  39. Driver driver = (Driver) aClass.newInstance();
  40. DriverManager.registerDriver(driver);
  41. Connection connect = driver.connect(url, properties);
  42. System.out.println(connect);
  43. }
  44. /**
  45. * @description: 使用Class.forName 自动完成注册驱动,简化代码
  46. * //这种方式获取连接是使用的最多,推荐使用
  47. * 使用反射加载了 Driver类
  48. * 在加载 Driver类时,完成注册
  49. * 源码:
  50. //
  51. // Register ourselves with the DriverManager
  52. // 在DriverManager中自动注册(Driver)
  53. //
  54. static {
  55. try {
  56. java.sql.DriverManager.registerDriver(new Driver());
  57. } catch (SQLException E) {
  58. throw new RuntimeException("Can't register driver!");
  59. }
  60. }
  61. * 1. 静态代码块,在类加载时,会执行一次.
  62. * 2. DriverManager.registerDriver(new Driver());
  63. * 3. 因此注册driver的工作已经完成
  64. */
  65. @Test
  66. public void test4() throws ClassNotFoundException, SQLException {
  67. // com.mysql.jdbc.Driver 初始化时:自动注册
  68. // DriverManager.registerDriver(new Driver());
  69. Class.forName(driverClassName);
  70. Connection connection = DriverManager.getConnection(url, properties);
  71. System.out.println(connection);
  72. }
  73. /**
  74. * @description: 在方式4的基础上改进,增加配置文件,让连接mysql更加灵活
  75. */
  76. @Test
  77. public void test5() throws IOException, SQLException, ClassNotFoundException {
  78. Properties properties = new Properties();
  79. // 使用类加载器的流操作会NPE, 未找到bug.可能和 单元测试/main方法 的相对资源路径有关(当前是子Module下新建resources包)
  80. // InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("resources/MyJDBC.properties");
  81. // properties.load(inputStream);
  82. //通过Properties对象获取配置文件的信息
  83. properties.load(new FileInputStream("resources/MyJDBC.properties"));
  84. //正常情况不写也自动注册. 建议写上, 防止自动配置的文件出问题
  85. Class.forName(driverClassName);
  86. Connection connection = DriverManager.getConnection(
  87. properties.getProperty("url"),
  88. properties.getProperty("user"),
  89. properties.getProperty("password")
  90. );
  91. System.out.println(connection);
  92. }
  93. }
  1. - 简单的select执行
  2. - // 使用Statement
  1. @Test
  2. public void testStatement() throws SQLException, ClassNotFoundException, IOException {
  3. // 1.注册驱动
  4. Class.forName("com.mysql.jdbc.Driver");
  5. // 2.获取连接
  6. Properties properties = new Properties();
  7. properties.load(new FileReader("resources/MyJDBC.properties"));
  8. Connection connection = DriverManager.getConnection(
  9. properties.getProperty("url"),
  10. properties
  11. );
  12. // Statement演示
  13. // 3.1 获取Statement
  14. Statement statement = connection.createStatement();
  15. // 3.2 创建并执行sql(返回ResultSet结果集)
  16. String selectSql = "select * from user";
  17. ResultSet resultSet = statement.executeQuery(selectSql);
  18. // 3.3 取出Result数据
  19. while (resultSet.next()){
  20. int id = resultSet.getInt(1);
  21. String name = resultSet.getString(2);
  22. String sex = resultSet.getString(3);
  23. System.out.println(id + "\t" + name + "\t" + sex);
  24. }
  25. // 4. 关闭连接
  26. resultSet.close();
  27. statement.close();
  28. connection.close();
  29. }
  1. - // 使用预编译PreparedStatement, 防止sql注入. (并有批处理功能)
  1. // preparedStatement演示
  2. // 3.2 创建sql
  3. String selectSql = "select * from user where id = ? and `name` = ?";
  4. // 3.1 获取preparedStatement
  5. PreparedStatement preparedStatement = connection.prepareStatement(selectSql);
  6. // 3.3 给占位符赋值
  7. preparedStatement.setInt(1,1); // 占位符从1开始
  8. preparedStatement.setString(2, "饶政");
  9. // 3.4 执行sql,并获取ResultSet; (获取预编译Statement时已传入sql,并占位赋值. 之后的执行语句再传参sql会覆盖)
  10. ResultSet resultSet = preparedStatement.executeQuery();
  11. // 3.5 取出Result数据
  12. while (resultSet.next()){
  13. int id = resultSet.getInt(1);
  14. String name = resultSet.getString(2);
  15. String sex = resultSet.getString(3);
  16. System.out.println(id + "\t" + name + "\t" + sex);
  17. }
  1. - <br />
  2. - 表与结果(Statement)
  3. - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12524106/1625919530752-b50cf38d-d29d-4cd9-adcf-8fa895b1b959.png#clientId=udfe4ac72-e1e7-4&from=paste&height=183&id=u3073062a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=183&originWidth=591&originalType=binary&ratio=1&size=17743&status=done&style=none&taskId=u20f951cc-73b4-48b5-9fe4-48796d9994e&width=591)
  1. 1 饶政
  2. 2 root
  3. 10 十号
  1. - ResultSet结果集源码
  2. - ArrayList[ byte[][] ]
  3. - ![捕获.PNG](https://cdn.nlark.com/yuque/0/2021/png/12524106/1625919642231-9570f9cf-c6c7-4f52-9c20-4df84bd620a4.png#clientId=udfe4ac72-e1e7-4&from=paste&id=u33b0cdd2&margin=%5Bobject%20Object%5D&name=%E6%8D%95%E8%8E%B7.PNG&originHeight=798&originWidth=1204&originalType=binary&ratio=1&size=140366&status=done&style=none&taskId=u6f5c1422-166a-4e45-a579-56d9c04bfa3)
  4. - DML语句删改查操作
  1. @Test
  2. public void testPreparedStatementDML() throws SQLException, ClassNotFoundException, IOException {
  3. // 1.注册驱动
  4. Class.forName("com.mysql.jdbc.Driver");
  5. // 2.获取连接
  6. Properties properties = new Properties();
  7. properties.load(new FileReader("resources/MyJDBC.properties"));
  8. Connection connection = DriverManager.getConnection(
  9. properties.getProperty("url"),
  10. properties
  11. );
  12. // 生成预编译命令对象, 并执行响应execute/Query语句.
  13. // String sql = "insert into user values (?,?,?)";
  14. // String sql = "update user set name = ? where id = ?";
  15. String sql = "delete from user where id = ? and name = ?";
  16. PreparedStatement preparedStatement = connection.prepareStatement(sql);
  17. // preparedStatement.setInt(1,11);
  18. // preparedStatement.setString(2,"rz");
  19. // preparedStatement.setString(3,"男");
  20. //
  21. // preparedStatement.setString(1,"ryze");
  22. // preparedStatement.setInt(2,11);
  23. //
  24. preparedStatement.setInt(1,11);
  25. preparedStatement.setString(2,"ryze");
  26. boolean execute = preparedStatement.execute();
  27. System.out.println(execute);
  28. // 4. 关闭连接
  29. preparedStatement.close();
  30. connection.close();
  31. }

3.JDBC API

点击查看【processon】

类结构

  • Y3]G3MOMQLI%8UKLZ1KYH~P.jpg

    4.JDBC工具类:

    封装 JDBCUtils 【关闭连接, 得到连接】

  • image.png

    代码实现

    1. - 工具类

    ```java

public class JdbcUtils {

  1. private static String driver; //驱动名
  2. private static String url; // url
  3. private static String user; //用户名
  4. private static String password; //密码
  5. private static Properties properties; //配置文件
  6. static {
  7. properties = new Properties();
  8. try {
  9. properties.load(new FileReader("MyJDBC/resources/MyJDBC.properties"));
  10. } catch (IOException e) {
  11. // 将编译异常向上抛成运行异常, 选择性处理. 下同
  12. throw new RuntimeException(e);
  13. }
  14. driver = properties.getProperty("driver");
  15. url = properties.getProperty("url");
  16. user = properties.getProperty("user");
  17. password = properties.getProperty("password");
  18. }
  19. /**
  20. * @description: 获取连接
  21. * @param:
  22. * @return: java.sql.Connection
  23. * @date: 2021/7/11 16:58
  24. */
  25. public static Connection getConnection(){
  26. Connection connection = null;
  27. try {
  28. connection = DriverManager.getConnection(url, user, password);
  29. } catch (SQLException e) {
  30. throw new RuntimeException(e);
  31. }
  32. System.out.println("-----------------------JdbcUtils类-Connection连接-已获取: " + connection);
  33. return connection;
  34. }
  35. /**
  36. * @description: 关闭资源
  37. * @param: resultSet

statement connection

  1. * @return: void
  2. * @date: 2021/7/11 16:57
  3. */
  4. public static void closeResources(ResultSet resultSet, Statement statement, Connection connection){
  5. try {
  6. if (resultSet != null){
  7. resultSet.close();
  8. System.out.println("-----------------------JdbcUtils类-ResultSet:" + resultSet.getCursorName() + "-已关闭-" + resultSet);
  9. }
  10. if (statement != null){
  11. statement.close();
  12. System.out.println("-----------------------JdbcUtils类-Statement命令语句:" + "-已关闭-" + statement);
  13. }
  14. if (connection != null){
  15. connection.close();
  16. System.out.println("-----------------------JdbcUtils类-Connection连接:" + "-已关闭-" + connection);
  17. }
  18. } catch (SQLException e) {
  19. throw new RuntimeException(e);
  20. }
  21. }

}

  1. - DML语句测试
  2. //(Connection连接关闭后, 对象依然有内存地址. 若继续对其操作,则 MySQLNonTransientConnectionException:连接关闭后,不允许进行任何操作)
  3. ```java
  4. /**
  5. * @description: DML语句测试Util的获取/关闭连接
  6. */
  7. public static void main(String[] args) {
  8. // 1.获取连接
  9. Connection connection = JdbcUtils.getConnection();
  10. PreparedStatement preparedStatement = null;
  11. ResultSet resultSet = null;
  12. try {
  13. // 2.操作sql
  14. preparedStatement = connection.prepareStatement("select * from user");
  15. resultSet = preparedStatement.executeQuery();
  16. while (resultSet.next()){
  17. int id = resultSet.getInt(1);
  18. String name = resultSet.getString(2);
  19. String sex = resultSet.getString(3);
  20. System.out.println(id + "\t" + name + "\t" + sex);
  21. }
  22. } catch (SQLException e) {
  23. e.printStackTrace();
  24. } finally {
  25. // 3.关闭连接
  26. // close后 Connection依然有内存地址
  27. JdbcUtils.closeResources(resultSet,preparedStatement, connection);
  28. System.out.println("资源关闭结束");
  29. }
  30. // 其它测试: 尝试在关闭连接后操作连接
  31. try {
  32. PreparedStatement testPreparedStatement1;
  33. // 出现异常 MySQLNonTransientConnectionException:连接关闭后,不允许进行任何操作
  34. testPreparedStatement1 = connection.prepareStatement("select * from user");
  35. } catch (SQLException e) {
  36. e.printStackTrace();
  37. }
  38. }
  1. - 结果
  2. - // 异常栈起始上文中35行 " connection.prepareStatement()"方法调用
  1. -----------------------JdbcUtils类-Connection连接-已获取: com.mysql.jdbc.JDBC4Connection@5f2108b5
  2. 1 饶政 1
  3. 2 root
  4. 10 十号
  5. 11 rz
  6. -----------------------JdbcUtils类-ResultSet:-已关闭-com.mysql.jdbc.JDBC42ResultSet@13805618
  7. -----------------------JdbcUtils类-Statement:-已关闭-com.mysql.jdbc.JDBC42PreparedStatement@56ef9176: select * from user
  8. -----------------------JdbcUtils类-Connection连接:-已关闭-com.mysql.jdbc.JDBC4Connection@5f2108b5
  9. 资源关闭结束
  10. com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
  11. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  12. at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
  13. at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
  14. at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
  15. at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
  16. at com.mysql.jdbc.Util.getInstance(Util.java:408)
  17. at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:919)
  18. at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:898)
  19. at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:887)
  20. at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:861)
  21. at com.mysql.jdbc.ConnectionImpl.throwConnectionClosedException(ConnectionImpl.java:1182)
  22. at com.mysql.jdbc.ConnectionImpl.checkClosed(ConnectionImpl.java:1177)
  23. at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4037)
  24. at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4006)
  25. at com.ryze.myJdbcUtils.JdbcUtils.main(JdbcUtils.java:118)

5.数据源中的: 数据库连接池 DataSource

示意图

image.png

种类

image.png

代码

  1. - 获取一个简单的druid连接池连接
  1. public static void main(String[] args) throws Exception {
  2. //1. 加入 Druid jar 包
  3. // <dependency>
  4. // <groupId>com.alibaba</groupId>
  5. // <artifactId>druid</artifactId>
  6. // <version>1.2.6</version>
  7. // <type>pom</type>
  8. // </dependency>
  9. // 2. 加入 配置文件 druid.properties
  10. // 3. 创建 Properties 对象, 读取配置文件
  11. Properties druidProperties = new Properties();
  12. druidProperties.load(StartSystemTest.class.getClassLoader().getResourceAsStream("druid.properties"));
  13. //4. 创建一个指定参数的数据库连接池, Druid 连接池
  14. DataSource dataSource = DruidDataSourceFactory.createDataSource(druidProperties);
  15. // 5.获取连接
  16. Connection connection = dataSource.getConnection();
  17. System.out.println(connection);
  18. // 6.回收连接
  19. connection.close();
  20. }
  1. - druid.properties
  1. #驱动加载
  2. driverClassName=com.mysql.jdbc.Driver
  3. #url地址
  4. url=jdbc:mysql://localhost:3306/myProject01_supermarketManagement
  5. #连接数据库的用户名
  6. username=root
  7. #连接数据库的密码
  8. password=0000
  9. #属性类型的字符串,通过别名的方式配置扩展插件, 监控统计用的stat 日志用log4j 防御sql注入:wall
  10. filters=stat
  11. #初始化时池中建立的物理连接个数。
  12. initialSize=2
  13. #最大的可活跃的连接池数量
  14. maxActive=300
  15. #获取连接时最大等待时间,单位毫秒,超过连接就会失效。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
  16. maxWait=60000
  17. #连接回收器的运行周期时间,时间到了清理池中空闲的连接,testWhileIdle根据这个判断
  18. timeBetweenEvictionRunsMillis=60000
  19. minEvictableIdleTimeMillis=300000
  20. #用来检测连接是否有效的sql,要求是一个查询语句。
  21. validationQuery=SELECT 1
  22. #建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。
  23. testWhileIdle=true
  24. #申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。设置为false
  25. testOnBorrow=false
  26. #归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能,设置为flase
  27. testOnReturn=false
  28. #是否缓存preparedStatement,也就是PSCache。
  29. poolPreparedStatements=false
  30. #池中能够缓冲的preparedStatements语句数量
  31. maxPoolPreparedStatementPerConnectionSize=200

6.Apache DBUtils

引入

  1. - 解决返回到Java程序的ResultSet结果集中的数据复用等问题<br /> ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12524106/1626331852167-12b09864-eab3-4fff-812f-3df60c724af8.png#clientId=uae08a51d-1c7a-4&from=paste&id=u8be20a83&margin=%5Bobject%20Object%5D&name=image.png&originHeight=710&originWidth=1773&originalType=binary&ratio=1&size=463121&status=done&style=none&taskId=ue7e2b1b3-d70e-48a6-882b-06539b6ab82)

概述

  1. - commons-dbutils Apache的一个开源JDBC工具库, 它是对JDBC的简单封装. 极大简化jdbc编码的工作量

7.DbUtils类

QueryRunner类:

封装了SQL的执行, 线程安全. 可CRUD, batch

ResultSetHandler接口:

用于处理 Java.lang.ResultSet, 将数据通过对应Handler转换成另一种形式

  1. - ArrayHandler:把结果集中的第一行数据转成对象数组。
  2. - ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
  3. - BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
  4. - BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
  5. - ColumnListHandler:将结果集中某一列的数据存放到List中。
  6. - KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key
  7. - MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
  8. - MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
  9. - ScalarHandler:查询单个值对象(标量对象)

DBUtils + Druid

DQL简单使用示例:

  1. //使用 apache-DBUtils 工具类 + druid 完成对表的 crud 操作
  2. public static void main(String[] args) throws Exception {
  3. //1. 通过德鲁伊连接池获取连接
  4. Properties properties = new Properties();
  5. properties.load(StartSystemTest.class.getClassLoader().getResourceAsStream("druid.properties"));
  6. DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
  7. Connection connection = dataSource.getConnection();
  8. System.out.println(connection);
  9. // 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project
  10. //2.创建 QueryRunner
  11. QueryRunner queryRunner = new QueryRunner();
  12. //3. 执行相关的方法,返回 ArrayList 结果集
  13. String sql = "select * from test where id <= ?";
  14. List<Object[]> list = queryRunner.query(connection, sql, new ArrayListHandler(),10);
  15. for (Object[] arr : list) {
  16. for (Object object : arr) {
  17. System.out.print(object + "\t");
  18. }
  19. System.out.println();
  20. }
  21. //老韩解读
  22. // (1) query 方法就是执行 sql 语句,得到 resultset ---封装到 --> ArrayList 集合中
  23. // (2) 返回集合
  24. // 参数说明
  25. // (3) connection: 连接
  26. // (4) sql : 执行的 sql 语句
  27. // (5) new ArrayListHandler() : 返回ArrayList, 元素为数组
  28. // 常用Handler: new BeanListHandler<>(Actor.class): 在将 resultset -> Actor 对象 -> 封装到 ArrayList
  29. // 底层使用反射机制 去获取 Actor 类的属性,然后进行封装
  30. // (6) 10: 占位符赋值,可以有多个值: 可变参数 Object... params
  31. // (7) 底层得到的 ResultSet ,会在 query 关闭, 关闭 PreparedStatement
  32. //释放资源(将德鲁伊连接返回连接池. 其它连接由DBUtils内部自动释放)
  33. System.out.println(connection); // com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@25618e91
  34. // 有德鲁伊连接池管理. 其close 返回连接池
  35. connection.close();
  36. }

queryRunner.query( Connection conn, String sql, ResultSetHandler rsh, Object… params ) 源码分析

  1. public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
  2. return this.<T>query(conn, false, sql, rsh, params);
  3. }
  4. // 调用如下的重载 query(...)
  5. /**
  6. param: closeConn 连接是否关闭
  7. */
  8. private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
  9. if (conn == null) {
  10. throw new SQLException("Null connection");
  11. }
  12. if (sql == null) {
  13. if (closeConn) {
  14. close(conn);
  15. }
  16. throw new SQLException("Null SQL statement");
  17. }
  18. if (rsh == null) {
  19. if (closeConn) {
  20. close(conn);
  21. }
  22. throw new SQLException("Null ResultSetHandler");
  23. }
  24. PreparedStatement stmt = null;
  25. ResultSet rs = null;
  26. T result = null;
  27. try {
  28. stmt = this.prepareStatement(conn, sql);
  29. this.fillStatement(stmt, params);
  30. rs = this.wrap(stmt.executeQuery());
  31. result = rsh.handle(rs);
  32. } catch (SQLException e) {
  33. this.rethrow(e, sql, params);
  34. } finally {
  35. try {
  36. close(rs);
  37. } finally {
  38. close(stmt);
  39. if (closeConn) {
  40. close(conn);
  41. }
  42. }
  43. }
  44. return result;
  45. }

7.BasicDao及至数据库持久层的设计

引出

  1. - DBUtils + 数据库连接池 简化了JDBC开发, 但仍有不足:
  2. 1. 通用性: 通过传参进行动态sql
  3. 1. 扩展性: 添加泛型动态确定JavaBean类型

BasicDao(同BaseDao) - BeanDaoImpl - JavaBean - 数据库表中的设计关联

image.pngimage.png

基本说明

DAO: Data Access Object - 数据访问对象

  1. 1. 这样的通用类(抽象), 可作为 BasicDao, 专与数据库交互, 即完成对数据(表)的CRUD等操作
  2. 2. BasicDao的基础上, 实现一张表和对应表的DAO, 更好地完成功能.

附: MySQL与JavaBean类型对应
AAA.png