文章目录
问题
1 原理
@Autowrite
private IUserDao dao;
dao.selectList();
2 . Mybatis 涉及到的设计模式
自定义持久层框架
JDBC分析
jdbc代码
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis? characterEncoding=utf-8", "root", "root");
// 定义sql语句?表示占位符
String sql = "select * from user where username = ?";
// 获取预处理statement
preparedStatement = connection.prepareStatement(sql);
// 设置参数,第⼀个参数为sql语句中参数的序号(从1开始),第⼆个参数为设置的参数值
preparedStatement.setString(1, "tom");
// 向数据库发出sql执⾏查询,查询出结果集
resultSet = preparedStatement.executeQuery();
// 遍历查询结果集
while (resultSet.next()) {
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
// 封 装 User user.setId(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()
存在问题
实际工作中,需求发生改变时候,sql也会改变。如果是硬编码,那么就要频繁改动代码
- 数据库连接频繁创建释放
- sql语句中存在硬编码,造成代码不宜维护。实际工作中sql经常需要变动
- 使用preparedStatement占有符进行参数传递,实际工作中参数不一定
- 查询结果时,存在硬编码问题(取列名),并且麻烦。
解决
①使⽤数据库连接池初始化连接资源
②将sql语句抽取到xml配置⽂件中
③使⽤反射、内省等底层技术,⾃动将实体与表进⾏属性与字段的⾃动映射
自定义框架
使用端
1.提供两个配置文件
sqlMapConfig.xml : 存放数据源信息,引⼊mapper.xml
引⼊mapper.xml 是因为只需要加载一次文件(sqlMapConfig.xml ),这样可以减少io操作和解耦
mapper.xml Mapper.xml : sql语句的配置⽂件信息
框架端
1.读取配置文件:根据配置文件路径加载成字节输入流存储在内存当中
加载Resource类:InputSteam getReSource(String path)
2. 创建javaBean保存加载信息
(1) Configuration(核心配置类) : 存放数据库基本信息、Map<唯⼀标识,Mapper> 唯⼀标识:namespace + "."
+ id
(2) MappedStatement(映射配置类):sql语句、statement类型、输⼊参数java类型、输出参数java类型
-
解析配置文件 dom4j
创建sqlSessionFactoryBuilder类:
⽅法:sqlSessionFactory build():
第⼀:使⽤dom4j解析配置⽂件,将解析出来的内容封装到Configuration和MappedStatement中
第⼆:创建SqlSessionFactory的实现类DefaultSqlSession(工厂模式)
-
创建SqlSessionFactory接口及实现类DefaultSqlSession
⽅法:openSession() : 获取sqlSession接⼝的实现类实例对象
-
创建sqlSession接⼝及实现类:主要封装crud⽅法
⽅法:
selectList(String statementId,Object param):查询所有selectOne(String statementId,Object param):查询单个
具体实现:封装JDBC完成对数据库表的查询操作
-
创建Executor接口及实现类
query():执行的就是JDBC代码
涉及到的设计模式:
Builder构建者设计模式、⼯⼚模式、代理模式
https://www.processon.com/diagraming/617fd7d7e0b34d1a7ea51228
Mybatis配置文件解析
SqlMapConfig层级关系
层级关系必须按照顺序来
<configuration >
<properties></properties> 为下面的文件引入properties文件,取值方式为${}
<settings></settings>
<typeAliases></typeAliases> 给全限定类名设置别名
<typeHandlers></typeHandlers>
<objectFactory></objectFactory>
<plugins></plugins>
<environments default="">
<environment id="">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<databaseIdProvider ></databaseIdProvider>
<mappers></mappers>
</configuration>
environments标签
事务管理器(transactionManager)类型
•JDBC:这个配置就是直接使⽤了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作
⽤域。
•MANAGED:这个配置⼏乎没做什么。它从来不提交或回滚⼀个连接,⽽是让容器来管理事务的整个⽣ 命周期(⽐如 JEE 应⽤服务器的上下⽂)。 默认情况下它会关闭连接,然⽽⼀些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻⽌它默认的关闭⾏为。
主要使用jdbc的方式
数据源(dataSource)类型
•UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
•POOLED:这种数据源的实现利⽤“池”的概念将 JDBC 连接对象组织起来。
•JNDI:这个数据源的实现是为了能在如 EJB 或应⽤服务器这类容器中使⽤,容器可以集中或在外部配置数据源,然后放置⼀个 JNDI 上下⽂的引⽤。
主要使用pooled的方式
mapper标签
•使⽤相对于类路径的资源引⽤,例如:<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
•使⽤完全限定资源定位符(URL),例如: <mapper class="org.mybatis.builder.AuthorMapper"/>
•将包内的映射器接⼝实现全部注册为映射器,例如:<package name="org.mybatis.builder"/>
如果同时使用,package要放在最后面
Properties标签
实际开发中,习惯将数据源的配置信息单独抽取成⼀个properties⽂件,该标签可以加载额外配置的properties⽂件
相当于把数据存放到jdbc.properties文件中,再配置文件中用${}取值
<!--加载外部的properties文件--> <properties resource="jdbc.properties"></properties>
typeAliases
设置别名有两种方式
1 单独设置
<!--给实体类的全限定类名给别名--> <typeAliases> <!--给单独的实体起别名--> <typeAlias type="com.lagou.pojo.User" alias="user"></typeAlias> </typeAliases>
2 设置包名
已经设置了一部分别名,如包装类,Stirng等
<!--给实体类的全限定类名给别名--> <typeAliases> <!--批量起别名:该包下所有的类的本身的类名:别名还不区分大小写--> <package name="com.lagou.pojo"/> </typeAliases> 为所有pojo下面的包设置别名,如com.lagou.pojo.user 别名为User 或许user USEr 等,不设置大小写
Mapper
resultMap
用来对应数据库列名和实体名称
id 唯一表示,其他《select resultTpye="id"》type 封装实体全类名<resultMap id="orderMap" type="com.lagou.domain.Order"> <result column="uid" property="user.id"></result> <result column="username" property="user.username"></result> <result column="password" property="user.password"></result> <result column="birthday" property="user.birthday"></result></resultMap>
association
中文为联合的意思,用于多表查询,共有两种方式
1.使用select
column :数据库列名,用于select作为参数 property:resultMap标签中需要映射的实体类字段名称 select:方法id <association column="user_id" property="user" select="com.ljy.inspector.dao.UserDao.findById"> </association>
具体使用
<resultMap id="projectMap" type="com.ljy.inspector.entity.Project"> <id column="id" property="id"/> //使用自定义类型转换器 <result column="state" property="state" typeHandler="com.ljy.inspector.type_handler.ItemStateHandler"/> <association column="user_id" property="user" select="com.ljy.inspector.dao.UserDao.findById"> </association></resultMap><select id="findById" resultType="com.ljy.inspector.entity.User"> SELECT * FROM user AS u <where> u.id = #{id} </where></select>
2.直接sql映射
<resultMap id="projectMap" type="com.ljy.inspector.entity.Project"> <id column="id" property="id"/> <result column="state" property="state" typeHandler="com.ljy.inspector.type_handler.ItemStateHandler"/> <association property="user" javaType="com.ljy.inspector.entity.User"> <id column="u_id" property="id"/> <result column="username" property="username"/> </association></resultMap>
3 两种方式的区别
1.如果使用了select属性,则本质上要进行两次查询,得到两张结果表,因为是从不同的表中查询(相同也无所谓)且每次只查询一个表,所以二者互不干涉,所以不存在字段歧义的问题,自动映射会开启。
2.如果使用resultMap属性,或者association本身当做一个resultMap,则本质是对多张表的一次联合查询,只产生一张结果表。然后对这张结果表一次进行映射。可能存在字段歧义问题,自动映射会关闭(如果没有指明映射关系的字段会得到空值)。此时要把产生歧义的字段起别名,并且把所有需要映射的字段都显式写出来。
collection
1 使用select
<!-- column="{qid=id,sort=sort} 前面的 qid/sort是定义的变量名, 后面的 id/sort是主表的字段id/sort,先查出主表的结果, 然后主表记录数是几 就执行几次 collection 的select,javaType 集合ofType 每一个元素的类型select的值: 对应xml的namespace + 对应xml中的代码片段的id,column作为select语句的参数传入,如果只传一个参数id可以简写: column="id" --><collection property="options" javaType="java.util.ArrayList" ofType="com.xxx.modules.xxx.entity.QuestionOption" select="com.xxx.modules.xxx.mapper.QuestionOptionMapper.selectList" column="{qid=id,sort=sort}" />
2.直接sql映射
property :实体熟悉名字<collection property="options" javaType="java.util.ArrayList" ofType="com.xxx.modules.data.entity.QuestionOption"> <id column="oid" property="id" jdbcType="VARCHAR" /> <result column="ocontent" property="content" jdbcType="VARCHAR" /> <result column="osort" property="sort" jdbcType="INTEGER" /></collection>
3 区别
直接sql映射结果集分页顺序会错乱
原理太复杂,学不会
动态ql语句
if
数字类型<if test="id != null"></if><if test='id != null and id > 28'></if>字符串类型<if test="username != null"></if><if test="username != null and '' != username"></if><if test="username != null and username.indexOf('ji') == 0"> </if><if test="username != null and username.indexOf('ji') >= 0"> </if><if test="username != null and username.lastIndexOf('ji') > 0"></if>
where
我不说,你难道不懂?
foreach
我不说,你也应该懂?
<foreach collection="array" open="id in(" close=")" item="id" separator=",">#{id}</foreach>
foreach标签的属性含义如下: 标签⽤于遍历集合,它的属性:
•collection:代表要遍历的集合元素,注意编写时不要写#{}
•open:代表语句的开始部分
•close:代表结束部分
•item:代表遍历集合的每个元素,⽣成的变量名
•sperator:代表分隔符
SQL⽚段抽取
Sql 中可将重复的 sql 提取出来,使⽤时⽤ include 引⽤即可,最终达到 sql 重⽤的⽬的
<sql id="selectUser" select * from User</sql><select id="findById" parameterType="int" resultType="user"> <include refid="selectUser"></include> where id=#{id}</select>
Mybatis复杂映射开发
一对一
使用association标签进行对应
一对多
使用collection 标签进行对应
多对多
写法与一对多一致,只是数据库表现房室不一样(sql不一样)
注解
基本注解
@Insert:实现新增@Update:实现更新@Delete:实现删除@Select:实现查询@Result:实现结果集封装@Results:可以与@Result ⼀起使⽤,封装多个结果集@One: 实 现 ⼀ 对 ⼀ 结 果 集 封 装 @Many:实现⼀对多结果集封装
基本使用
1.修改sqlMapConfig.xml
<mappers> <!--扫描使⽤注解的类--> <mapper class="com.lagou.mapper.UserMapper"></mapper></mappers>
缓存
sqlSession(一级缓存)
-
在sqlSession中存在HashMap存放数据,不同的sqlSeesion的缓存是不同的。
-
第⼀次发起查询⽤户id为1的⽤户信息,先去找缓存中是否有id为1的⽤户信息,如果没有,从 数据库查询⽤户信息。得到⽤户信息,将⽤户信息存储到⼀级缓存中。
-
如果中间sqlSession去执⾏commit操作(执⾏插⼊、更新、删除),则会清空SqlSession中的 ⼀级缓存,这样做的⽬的为了让缓存中存储的是最新的信息,避免脏读。
-
第⼆次发起查询⽤户id为1的⽤户信息,先去找缓存中是否有id为1的⽤户信息,缓存中有,直 接从缓存中获取⽤户信息
源码
缓存的数据结构是一个map,key值是由MapperStartMentId,params,sql,分页参数组成
Mapper(二级缓存)
与一级类似,带更新ing
代码附录
自定义持久层框架
使⽤端
sqlMapConfig.xml
mapper.xml
User实体
框架段
Configuration
MappedStatement
Resources
SqlSessionFactoryBuilder
XMLConfigerBuilder