回到目录:
OrangeZh:拉勾教育:JAVA高薪训练营 学习笔记zhuanlan.zhihu.com介绍
自定义持久层框架Demo,此Demo仅为个人学习编写,目前实现了单条查询、所有查询以及单条的增删改
项目源码:去看源码
JDBC问题分析及解决思路
public void normalJdbc() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/ozdemo?characterEncoding = utf - 8", " root", " 123456");
// 定义sql ?代表占位符
String sql = "select * from user where username = ?";
// 获取预处理Statement
preparedStatement = connection.prepareStatement(sql);
//设置参数 第一个参数为参数位置(1开始),第二个参数为参数的值
preparedStatement.setString(1, "tom");
// 执行sql,获得查询结果
resultSet = preparedStatement.executeQuery();
// 变量结果
User user = new User();
while (resultSet.next()) {
int id = resultSet.getInt("uid");
String username = resultSet.getString("username");
// 封装结果
user.setUid(id);
user.setUsername(username);
}
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放资源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
问题总结:
- 连接频繁创建、释放造成了资源浪费,影响系统性能
- Sql语句在代码中硬编码,不易维护
- 结果集封装硬编码,不易维护
解决思路
- 使用连接池
- 使用配置文件维护sql
- 封装结果集使用反射、内省
自定义持久层框架思路
使用端(需要使用持久层的项目):引入自定义持久层的jar包
主要提供2部分配置信息:数据库配置信息、sql配置信息(包含:sql语句、参数类型、返回类型)
使用配置文件来提供这2部分配置信息:
- sqlMapConfig.xml:存放数据库配置信息,存放mapper.xml全路径
- mapper.xml:存放sql配置信息
自定义持久层框架本身(持久层框架jar):本质就是对JDBC代码进行封装
1、加载配置文件:根据配置文件的路径,加载配置文件成字节输入流,存储在内存中
创建Resources类 方法:InputStream getResourceAsSteam(String path)
2、创建2个javaBean(容器对象):存放的就是对配置文件解析出来的内容
Configuration:核心配置类:存放sqlMapConfig.xml解析出来的内容
MapperStatement:映射配置类:存放mapper.xml解析出来的内容
3、解析配置文件:dom4j
创建类:SqlSessionFactoryBUilder 方法:build(InputSteam in)
第一:使用dom4j解析配置文件,将解析出来的内容封装到容器对象中
第二:创建SqlSessionFactory对象,生产sqlSession:会话对象(工厂模式)
4、创建SqlsessionFactory接口及实现DefaultSqlSessionFactory
方法openSeeion():生产sqlSession
5、创建SqlSession接口及实现类DefaultSession
定义对数据库的curd操作:selectList()、selectOne()、update()、delete()、insert()
6、创建Excutor接口及实现类SimpleExcutor实现类
JDBC操作的执行过程:
1、注册驱动,获取连接
2、获取Sql语句 然后转换sql语句,并对#{}里面的值进行解析存储
3、获取预处理对象: preparedStatement
4、设置参数
5、执行sql
6、返回更新的条数
prepareStatement(Configuration configuration, MappedStatement mappedStatement, Object... params):准备预处理对象(1、2、3、4)
query(Configuration configuration, MappedStatement mappedStatement, Object... params):查询操作的执行(5、6)
update(Configuration configuration, MappedStatement mappedStatement, Object... params):增、删、改操作的执行(5、6)6)
自定义持久层框架测试
com.ozdemo.test.IPersistenceTest
public void test() throws Exception {
InputStream inputStream = Resources.getResourceAsSteam("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//查询
System.out.println("------------------ 查询 -------------------");
User user = new User();
user.setUid(1);
user.setUsername("张三");
IUserDao iUserDao = sqlSession.getMapper(IUserDao.class);
User resUser1 = iUserDao.findOne(user);
System.out.println("查询结果:" + resUser1.toString());
//新增
System.out.println();
System.out.println("------------------ 新增 -------------------");
User user1 = new User();
user1.setUsername("XX7");
int res1 = iUserDao.insertOne(user1);
System.out.println("添加成功条数:" + res1);
//修改
System.out.println();
System.out.println("------------------ 修改 -------------------");
User user2 = new User();
user2.setUid(1);
user2.setUsername("XX-update");
int res2 = iUserDao.updateOne(user2);
System.out.println("更新成功条数:" + res2);
//删除
System.out.println();
System.out.println("------------------ 删除 -------------------");
int res3 = iUserDao.deleteById(6);
System.out.println("删除成功条数:" + res3);
}
Mybatis框架核心
Configuration:初始化基础配置,所有的配置信息都在Configuration中
SqlSessionfactory:Sqlsession工厂
Sqlsession:Mybatis的顶层api,表示数据库交互的会话,完成数据库的增删查改的一些功能
Executor:Mybatis的执行器,是Mybatis调度的核心,负责sql语句的生成和查询缓存
StatementHandler:封装了JDBC Statement 操作
ParameterHandler:负责将传入的参数转化为JDBC Statment 的参数
ResultSethandler:负责将JDBC返回的Resultset集对象封装成返回集合
TypeHandler:负责将数据库的类型何实体类型之间的转化何映射
MappedStatement:MappedStatement是select,update,delete,insert节点的封装
SqlSource:负责根据用户传递的parameterObject 动态的生成一条sql语句
Boundsql:表示动态生成的sql何对应的参数信息
Mybatis执行过程
![d570c779cce81c8a7ff9190f63537d5c.png](https://i-blog.csdnimg.cn/blog_migrate/18268e194e4dd1d33e5d1a498f09da07.jpeg)
Mybatis相关问题
1、Mybatis动态sql是做什么的?都有哪些动态sql?简述一下动态sql的执行原理?
- 动态sql是通过在xml文件中添加条件判断标签,从而动态判断拼接成sql语句;
- 动态sql标签包括有:if、choose(when,otherwise)、trim、 where、set、foreach
- 动态sql其实就是使用Ognl表达式,通过sql的参数对象计算出表达式的值,然后进行动态的判断拼接
2、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
- Mybatis支持延迟加载,只能在resultMap中使用,支持一对一和一对多的延迟加载,分别使用association和cllection标签
- 原理:通过CGLib创建目标对象的代理对象,当调用目标对象的方法时,调用目标对象的查询方法,从而实现使用时再查询,减轻了数据库的压力;即当需要关联查询时再进行数据查询
3、Mybatis都有哪些Executor执行器?它们之间的区别是什么?
- Mybatis有3种Executor执行器:SimpleExecutor、ReuseExecutor、BatchExecutor
- 区别:
SimpleExecutor:每次执行都会创建一个Statement对象
ReuseExecutor:每次执行都会缓存Statement对象,并以sql作为可以,如果存在就直接使用,不存在就创建
BatchExecutor:批处理执行器,仅支持update,先将所有sql都通过addBatch()方法添加到批处理中,然后通过executeBatch()方法统一执行
- 可在Mybatis配置文件中配置默认执行器类型,也可以在创建SqlSession时传入ExecutorType参数
4、简述下Mybatis的一级、二级缓存(分别从存储结构、范围、失效场景。三个方面来作答)?
- 一级缓存:Mybatis的一级缓存是SqlSession下的缓存,作用在Sqlsession中,当Sqlsession关闭或者查询的数据update时缓存失效;内部使用HashMap进行存储,以CacheKey对象做为key,当查询时会先去查询缓存中是否存在,如果存在直接返回或者查询数据库
- 二级缓存:二级缓存属于Mapper的缓存,多个SqlSession共用二级缓存,当同一个Mapper中的增删改时缓存失效;内部同样使用HashMap进行存储,同样使用CacheKey对象做为key;Mybatis中默认不开启二级缓存,可通过cacheEnabled来设置是否开启二级缓存;在分布式环境下可配置redis等来做为二级缓存
5、简述Mybatis的插件运行原理,以及如何编写一个插件?
- Mybatis的4大组件ParameterHandler、ResultSetHandler、StatementHandler、Executor提供了扩展插件机制;Mybatis使用动态代理,来为需要拦截的接口生产代理对象,以实现接口方法拦截功能;
- 实现Interceptor接口并重写intercept()方法,然后加上@Interceptors注解,指定需要拦截的方法,将自定义的插件配置到配置文件中
下一篇:
OrangeZh:Mybatis应用及源码分析zhuanlan.zhihu.com回到目录:
OrangeZh:拉勾教育:JAVA高薪训练营 学习笔记zhuanlan.zhihu.com文章内容输出来源:拉勾教育 Java高薪训练营