基于JDBC改造, mybatisv1版本 1.综述
- 需求: 根据用户信息,查询用户列表
- 将JDBC中的硬编码,写入properties文件中
- 封装查询方法为查询列表函数
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.核心代码
- 加载配置文件
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 加载驱动
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;
- 配置文件
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.关键代码解析
- SimpleTypeRegistry
- org.apache.ibatis.type.SimpleTypeRegistry
- ibatis 内部有简单类型的 set 集合
SimpleTypeRegistry.isSimpleType(parameterType)
- 反射获取/设置 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");
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- Spring注解驱动第十讲--@Autowired使用
- SqlServer|sql server的UPDLOCK、HOLDLOCK试验
- jvm|【JVM】JVM08(java内存模型解析[JMM])
- 技术|为参加2021年蓝桥杯Java软件开发大学B组细心整理常见基础知识、搜索和常用算法解析例题(持续更新...)