java|【JavaEE高级】2-基于JDBC改造, mybatisv1版本

基于JDBC改造, mybatisv1版本 1.综述

  • 需求: 根据用户信息,查询用户列表
  1. 将JDBC中的硬编码,写入properties文件中
  2. 封装查询方法为查询列表函数
【java|【JavaEE高级】2-基于JDBC改造, mybatisv1版本】代码示例
2.业务流程
public static void main(String[] args) throws Exception { // 1 加载配置文件 loadProperties("mybatis.v1.properties"); // 2 执行查询 User query = new User(); query.setName("测试"); List users = selectList("queryUserListByName", query); System.out.printf("users: %s", users); }

3.核心代码
  1. 加载配置文件
private static Properties prop = new Properties(); private static void loadProperties(String filename) throws IOException { InputStream stream = MybatisV1.class.getClassLoader().getResourceAsStream("demo/" + filename); prop.load(stream); }

  1. 执行查询
// 1 加载驱动 Class.forName(prop.getProperty("db.driver")); // 2 创建连接 Connection connection = DriverManager.getConnection( prop.getProperty("db.url"), prop.getProperty("db.user"), prop.getProperty("db.password") ); // 3 SQL 预处理 PreparedStatement ps = connection.prepareStatement( prop.getProperty("db.sql." + statementId) ); // 3.1 获取入参类型 Class parameterType = Class.forName(prop.getProperty("db.sql." + statementId + ".parameterType")); // 3.2 简单类型 org.apache.ibatis.type.SimpleTypeRegistry if (SimpleTypeRegistry.isSimpleType(parameterType)) { ps.setObject(1, parameter); } else { // 3.3 对象类型 // 3.3.1 获取有序的参数, 能和 sql 中的 ? 一一对应 String[] parameters = prop.getProperty("db.sql." + statementId + ".parameters").split(","); // 3.3.2 反射取值, 设置到 ps 中 for (int i = 0; i < parameters.length; i++) { String name = parameters[i]; Field field = parameterType.getDeclaredField(name); field.setAccessible(true); Object value = https://www.it610.com/article/field.get(parameter); ps.setObject(i + 1, value); } }// 4 执行 SQL ResultSet rs = ps.executeQuery(); // 5 获取执行结果 // 5.1 获取结果集类型 Class resultType = Class.forName(prop.getProperty("db.sql." + statementId + ".resultType")); List resultList = new LinkedList<>(); while (rs.next()) { R result = (R) resultType.newInstance(); ResultSetMetaData metaData = https://www.it610.com/article/rs.getMetaData(); for (int i = 1; i < metaData.getColumnCount() + 1; i++) { String columnName = metaData.getColumnName(i); Field field = resultType.getDeclaredField(columnName); field.setAccessible(true); field.set(result, rs.getObject(columnName)); } resultList.add(result); }// 6 关闭连接 return resultList;

  1. 配置文件
db.driver=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://localhost:3306/jhome?characterEncoding=utf-8 db.user=root db.password=fc4fcafd-e86d-4fda-9a96-60147e94cc0fdb.sql.queryUserListByName=select * from user where name = ? # 内部类使用 $ 获取, 因为成的 .class 就是 A.class, A$B.class 这样的结构 db.sql.queryUserListByName.parameterType=com.aizain.jhome.mybatis.source.demo.MybatisV1$User db.sql.queryUserListByName.resultType=com.aizain.jhome.mybatis.source.demo.MybatisV1$User db.sql.queryUserListByName.parameters=name

4.关键代码解析
  1. SimpleTypeRegistry
  • org.apache.ibatis.type.SimpleTypeRegistry
  • ibatis 内部有简单类型的 set 集合
SimpleTypeRegistry.isSimpleType(parameterType)

  1. 反射获取/设置 Field
  • Class.getDeclaredField()
    • 获取声明的字段(注意: 是获取字段对象)
    • 可以取得全部字段, getField 只会获取 public 的
      • 不包括父类, getField 会获取父类的,
      • 可通过 getSuperclass().getDeclaredField() 获取父类的
    • Declared 声明的
    • 不可取出 private 的值
  • Class.setAccessible(boolean flag)
    • 设置访问权限
    • 让 Class.getDeclaredField() 可以取出 private 的值
    • 设置前会检查系统安全权限 sm.checkPermission(ACCESS_PERMISSION)
      • java.security.Permission ACCESS_PERMISSION = new ReflectPermission(“suppressAccessChecks”)
      • 设置 java 底层的安全问题, 暂不细纠
// 初始化数据 User user = new User(); user.setName("zain"); // 获取反射 name 字段对象 Class userClazz = User.getClass(); Field nameField = userClazz.getDeclaredField("name"); nameField.setAccessible(true); // 获取字段值 name = "zain" Object name = nameField.get(user); // 设置字段值 user.name = "zain2" nameField.set(user, "zain2");

    推荐阅读