Mybatis笔记
来源:互联网 发布:大数据分析就业 编辑:程序博客网 时间:2024/06/06 03:40
Mybatis知识点
1.mybatis是什么?
mybatis是一个持久层的框架,是apache下的顶级项目。
mybatis提供映射方式,自由灵活生成满足需要的sql语句。
可以将向preparedstatement中的输入参数自动进行输出映射。将查询结果集自动映射成java对象。(输出映射)
2.mybatis框架
3.入门程序
需求:根据用户id查询数据
根据用户名称模糊查询数据
删除、添加、更新用户。
要下载mybatis的jar包。https://github.com/mybatis/mybatis-3/releases
过程:
1. 创建一个po类
2. 创建映射文件,在映射文件中配置sql
<!-- namespace在这里是指数据库实例的名称 -->
<mappernamespace="orcl
">
<!-- 在这里配置sql语句 -->
<!-- 通过select完成查询 -->
<!-- 通过id查询用户
#{} 表示一个占位符
parameterType 表示参数的类型
#{id} 表示接入输入的参数是id,如果输入的是简单类型,则参数可以是任意,可以是value等
ResultType表示操作数据库结果所映射的Java对象类型
select中的ResultType表示查询结果的一条记录转成一个对象,一般为包名.类名
-->
<selectid="finduserbyid"parameterType="java.lang.Integer"resultType="com.ly.domain.User">
select* from user where id=#{id}
</select>
</mapper>
3. 在SqlMapConfig文件中配置映射文件的加载。
<mappers>
<mapperresource="sqlmap.User.xml"/>
</mappers>
4. 编写测试第一条(按id查询)
1)在xml中配置sql:
<!--通过select完成查询 -->
<!-- 通过id查询用户
#{} 表示一个占位符
parameterType 表示参数的类型
#{id} 表示接入输入的参数是id,如果输入的是简单类型,则参数可以是任意,可以是value等
ResultType表示操作数据库结果所映射的Java对象类型
select中的ResultType表示查询结果的一条记录转成一个对象
-->
<selectid="finduserbyid"parameterType="java.lang.Integer"resultType="com.ly.domain.User">
select * from users where id=#{id}
</select>
2)编写测试代码:
public classMybatisFirst {
//根据id查询用户信息
@Test
public static void finduserbyid() throwsException{
//配置文件
String str ="SqlMapConfig.xml";
InputStream ips = null;
SqlSessionFactory sessionfeactory =null;
SqlSession ss=null;
try {
//得到配置文件输入流
ips =Resources.getResourceAsStream(str);
//创建会话工厂,传入mybatis文件的配置信息。
sessionfeactory= newSqlSessionFactoryBuilder().build(ips);
//通过工厂得到sqlsession
ss = sessionfeactory.openSession();
//通过sqlsession操作数据库
//第一个参数:statement中的id=namespace+.+statement的id
//第二个参数:指定和映射文件中所匹配的parameterType的类型参数,也就是表中某一记录的id
User user=ss.selectOne("orcl.finduserbyid",1);
System.out.println(user);
} catch (IOException e) {
// TODO Auto-generated catchblock
e.printStackTrace();
}finally{
//关闭资源
ss.close();
ips.close();
//((InputStream)sessionfeactory).close();
}
}
}
5. 编写测试第二条(按名字模糊查询)
1)在User.xml中添加配置信息:
<!--${}表示拼接sql,即把传入的sql参数不加修饰拼接起来-->
<selectid="finduserbyname"parameterType="java.lang.String"resultType="com.ly.domain.User">
select * from users where name like‘%${value}%’
</select>
2)编写测试代码:
public voidfinduserbyname(){
SqlSessions2 = null;
try {
s2=common();
List<User>list = s2.selectList("orcl.finduserbyname","小");
for(User i:list){
System.out.println(i.getId()+"——————"+i.getName());
}
} catch (IOExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}finally{
s2.close();
}
}
6. 编写第三条(添加信息)
1)在xml文件中配置:
<!-- 添加用户
此时的参数类型应该时domain类,
#{}中写的是domain类中的属性,mybatis通过ognl获取对象的属性值-->
<insertid="addUser"parameterType="com.ly.domain.User">insert intousers(id,name) values(#{id},#{name}) </insert>
2)编写测试代码
public void addUser(){
SqlSession s3=null;
try {
s3 = common();
User user = new User();
user.setId(5);
user.setName("倩倩");
s3.insert("orcl.addUser",user);
s3.commit();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
7. 删除用户
a) Xml配置:
<!-- 删除用户-->
<deleteid="deleteUser"parameterType="java.lang.Integer">DELETE FROM USERS WHEREID=#{ID}</delete>
b) 编写测试代码:
public void deleteUser(){
SqlSession s4=null;
try {
s4 = common();
s4.delete("orcl.deleteUser", 6);
s4.commit();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
s4.close();
}
8. 修改用户
a) xml配置
<!-- 根据id修改用户 -->
<updateid="updateUserById"parameterType="com.ly.domain.User">
updateusers set name=#{name} where id=#{id}
</update>
b) 编写测试文件
publicvoid updateUserById(){
SqlSessions5=null;
try{
s5= common();
Useruser = new User();
user.setName("李燕燕");
user.setId(4);
s5.update("orcl.updateUserById",user);
s5.commit();
}catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}finally{
s5.close();
}
}
总结:
1、参数如果只有一个,parameterType为属性类型。超过一个,参数为对象(包名.类名)。
2、单元测试文件(Junit)应该导入三个包。
3、如果没有涉及到Dao层,则命名空间为数据库实例名,如果用到则为:dao接口的包名.类名。
4、#{}和${}的区别?
#{}表示一个占位符,接受传入的参数。传入的参数类型可为:简单类型,value,pojo对象,HashMap。当传入的是简单数据类型时,可写成value或其他名称。${}表示sql拼接,会引起sql注入,不建议使用,接受传入的参数,类型可为:简单类型,value,pojo对象,当传入的是简单类型,则只能为value。
9. 自增主键返回
1) Mysql自增:执行insert提交之前,自动生成自增主键。通过mysql的函数获取最新增加的主键。LAST_INSERT_ID(unsert之后调用)
Xml配置:
<!--只适用于mysql中的自增长主键
keyProperity:将获取到的主键值设置到parameterType中的那个属性中
order:sql语句的执行顺序,相对于insert语句的查询顺序
-->
<selectKeykeyProperty="id"order="AFTER" ResultType="java.lang.String">SELECT LAST_INSERT_ID</selectKey>
2) Oracle自增:通过序列
<selectKey keyProperty="id"order="AFTER" resultType="java.lang.Integer">SELECT序列名.nextval</selectKey>
3) Sql server自增:
10. 非自增主键
a) Mysql:使用uuid函数实现主键的非自增。需修改主键的类型为String,长度为35.即先用uuid随机生成一个id号,然后将主键放入sql中。
<selectKeykeyProperty="id" order="AFTER" resultType="java.lang.Integer">SELECTUIDD</selectKey>
b) Oracle:
11. Mybatis常用的接口和类:
1) SqlSession使用范围:是一个面向用户的接口。SqlSession提供很多操作数库的方法。(SelectOne,SelectList)线程不安全,在实现类中除了有操作数据库的方法,还有数据域的属性。最佳应用场合在方法体中,定义成局部变量。
2) SqlsessionFeactory:通过SqlsessionFeactory来创建SqlSession。使用单例模式创建SqlSessionFeactory。
3) SqlsessionFeactoryBuilder:通过SqlSessionFeactoryBuilder来创建SqlSessionFeactory。
12. 开发dao层:
1) 原始开发dao方法(需要程序员写dao接口和实现类)
需要向dao实现类中注入SqlSessionFeactory,然后再创建SqlSession。
a) dao接口:
publicinterface UserDao {
//根据id查询用户信息(由xml实现)
public User finduserbyid(int id) throwsException;
//添加用户信息
public void addUser(User user) throwsIOException;
//删除用户
public void deleteUser(int id);
}
b) dao接口实现类:
publicUser finduserbyid(int id) throws Exception {
// TODO Auto-generated method stub
SqlSession sqlsession = MybatisFirst.common();
User user =sqlsession.selectOne("orcl.finduserbyid",id);
sqlsession.close();
return user;
}
2) Mapper代理方法(只需要写mapper接口)
写个mapper接口(dao接口)
public interface UserDaoMapper {
//根据id查询用户信息(由xml实现)
public User finduserbyid(int id) throws Exception;
//添加用户信息
public void addUser(User user) throws IOException;
//删除用户
public void deleteUser(int id);
}
编写mapper.Xml映射文件
开发规范:“
a) Namespace是包名.类名。
b) Mapper.java中的方法名是mapper.Xml中的id
c) Mapper.java中方法的返回值是mapper.xml中的resultType。
d) Mapper.java中方法的参数是mapper.xml中的parameterType。
13. SqlMapConfig.xml
Mybatis的全局配置文件:
<configuration>
<environmentsdefault="development">
<environmentid="development">
<transactionManagertype="JDBC"/>
<dataSourcetype="POOLED">
<propertyname="driver"value="oracle.jdbc.OracleDriver"/>
<propertyname="url"value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>
<propertyname="username"value="Test"/>
<propertyname="password"value="test"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapperresource="com/ly/mapper/UserMapper.xml"/>
</mappers>
</configuration>
1> Properties属性
将url和driver,password,username配置在db.properties文件中,在需要的xml文件中用${username}…拼接。
<propertiesresource=”db.properties”></properties>
Mybatis加载属性的顺序:
在properties元素体内定义的属性首先被读取
然后会读取properties中的resource或者是url加载的属性,会覆盖已读取的同名属性。
最后读取parametertype传递的属性。会覆盖已读取的同名属性。
优先级:parametertype——resource——properties
2> Setting属性
调整运行参数(开启二级缓存等)
3> typeAlias(别名)
针对单个的别名定义:
<typeAliases>
<typeAlias type=”全路径” alias=”别名”>
</typeAliases>
批量定义别名:输入一个包名,会自动给所有po类定义别名。别名是类名,首字母大小写都可以。
<typeAliases>
<typeAlias type=”包名” >
</typeAliases>
4> 映射配置
<mappers>
单个映射文件的加载:
<mapper resource=”相对路径”>
通过mapper接口加载映射文件,规范,需将mapper接口类和mapperxml文件同名且放在一个目录下。这种方法的前提是使用了mapper代理的方法。
<mapper class=”接口的路径”/>
批量加载映射文件。规范,需将mapper接口类和mapperxml文件同名且放在一个目录下。这种方法的前提是使用了mapper代理的方法。
<package name=”mapper接口的包名”>
</mappers>
14. 输入参数映射
通过parametertype可指定输入类型。可以是:pojo包装类型,简单类型,hashmap类型。
Pojo包装对象做参数:
写一个查询条件包装类(假设为ComUser),再写一个扩展类。把需要的查询条件加入进去。
Xml配置:
ParameterType=”查询条件包装类的路径” 用${原pojo包装类名.属性名}获取传入的参数。
<select id=”comquery”parameterType=”查询条件包装类路径”>
SELECT SNO FROM USERSWHERE ID=${扩展类.id} AND SEX=${扩展类.sex}
15. 输出参数映射
1> Resulttype
使用resultType进行映射输出时,只有查询的字段和pojo类中属性名一致时才可以映射成功。
如果查询的字段名和pojo类中的字段都不一致,那么不会创建pojo对象。
如果查询的字段明和pojo类中有至少一个字段一致,那么会创建pojo对象。
输出简单类型:
ResultType=“int/String/Date…“
2> resultMap
如果查询的字段和pojo的属性不一致,定义一个resultMap对列明和pojo属性名之间做一个映射关系。
a) 定义resultMap
<!-- 定义resultMap
Type:resultmap最终所映射的Java对象类型,可以使用别名
id:对resultmap的唯一标识 -->
<resultMaptype="User"id="UserresultMap">
<!-- column:查询出的列名
property:resultmap中pojo类型中的属性名 -->
<idcolumn=""property=""/>
<!-- 对普通列的映射定义 -->
<resultcolumn=""property=""/>
</resultMap>
b) 使用resultMap作为statement输出映射类型
<selectid="finduserbyid"parameterType="java.lang.Integer"resultMap="刚才定义的resultmap">
select * from users where id=#{id}
</select>
如果此时用的resultmap是其他xml文件中的,则需要再调用时加上命名空间。
16. 动态sql
Mybatis的核心是,对sql语句进行灵活操作,通过表达式进行判断,对sql语句进行灵活拼接。
对传入的参数进行判断:如果不为空,则传入
用if进行判断。
<selectid="finduserbyid"parameterType="java.lang.Integer"resultType="com.ly.domain.User">
select * from users
<where>
<iftest="id!=null and id!=''">and id=#{id}</if>
<iftest="name!=null and name!=''">and name like'%${name}%'</if>
</where>
</select>
17. Sql片段
A) 定义:
<!-- 定义sql片段 ,基于单表定义sql片段,可重用高,sql片段中不要包含where-->
<sqlid="query_User_where">
<iftest="id!=null and id!=''">and id=#{id}</if>
<iftest="name!=null and name!=''">and name like'%${name}%'</if>
</sql>
B) 使用:
<where>
<!-- refid:指定sql片段的id,如果引用的sql片段不在当前xml中,需要加namespace -->
<includerefid="query_User_where"></include>
</where>
18. Foreach标签
19. 一对一查询
mapper.Xml中定义resultmap:
<resultMaptype="返回类型"id="用于表示这个resultmap">
column:查询出的列名
property:resultmap中pojo类型中的属性名
<id column=""property=""/>
对普通列的映射定义
<result column=""property=""/>
<!--association:用于映射关联查询单个用户的信息
property:要将关联查出来的信息映射到主信息pojo类的那个属性中 -->
<associationproperty="" javatype=“映射的java类型“></association>
<id cloumn=” ” property=” ”/>
<result cloumn=” ” property=” ” />
</resultMap>
配置映射关联的用户查询信息:
总结:
如过没有特殊要求,比如把查到信息的用户相关信息返回到一个user对象中,则使用resulttype。只需要把没有的字段对应的属性加入到pojo类中即可。
若是有特殊要求,则使用resultmap。进行resultmap定义时,关联的信息用标签association。进行配置。
Resultmap可以实现延迟加载,resulttype不可以。
20. 一对多查询
(比如:查询订单和订单明细)
定义resultmap:
<resultMaptype="返回类型"id="用于表示这个resultmap">
column:查询出的列名
property:resultmap中pojo类型中的属性名
<id column=""property=""/>
<!--对普通列的映射定义-->
<result column=""property=""/>
<!--association:用于映射关联查询单个用户的信息
property:要将关联查出来的信息映射到主信息pojo类的那个属性中 -->
<associationproperty="" javatype=“映射的java类型“></association>
<id cloumn=” ” property=” ”/>
<result cloumn=” ” property=” ” />
<!--订单明细信息 一个订单明细查询多条明细,要使用collection进行映射。collection是把查询出的多条结果映射到一个集合中-->
<collectionproperty="映射的类的那个属性"ofType="要映射到集合属性中pojo的类型">
<id column=”订单明细的主键(注意取别名)” porperity=”属性名”/>
<result/>
</collection>
</resultMap>
由于上边很多配置信息重复,所以可使用继承属性,提高代码的复用率。
<!-- 一对多查询的resultmap,和一对一查询映射重复的可以不用重新配置,直接用继承。 -->
<resultMaptype=""id=""extends=" 一对一查询的resulttype的id">
<!-- 订单信息 -->
<!-- 用户信息 -->
<!-- 订单明细信息 一个订单明细查询多条明细,要使用collection进行映射。collection是把查询出的多条结果映射到一个集合中-->
<collectionproperty="映射的类的那个属性"ofType="要映射到集合属性中pojo的类型">
<id/>
<result/>
</collection>
</resultMap>
总结:
Mybatis使用collection对多条关联信息映射到一个list集合属性中。如果使用resultype将订单明细信息映射到pojo类的定义的类对象属性中。需要自己处理:双重循环遍历,去重,加入list集合中。
21. 多对多查询
定义resultmap:
<resultMaptype="user"id="id">
<idcolumn=""property=""/>
<resultcolumn=""property=""/>
<!-- 订单信息 ,一个用户对u应多个订单信息,所以用collection-->
<collectionproperty="映射类的属性"ofType="要映射到集合中的pojo类型,即是list集合里放置的东西">
<id/>
<result/>
<!-- 订单明细信息 一个订单明细查询多条明细,要使用collection进行映射。collection是把查询出的多条结果映射到一个集合中-->
<collectionproperty="映射的类的那个属性"ofType="要映射到集合属性中pojo的类型">
<id/>
<result/>
</collection>
<!-- 商品信息,一个商品信息对应一个商品-->
<associationproperty="商品明细表对应的对象"javaType="商品信息表对应的pojo类">
<idcolumn=""property=""/>
<resultcolumn=""property=""/>
</association>
</collection>
</resultMap>
总结:
对查询结果有特殊要求的功能,使用resultmap。若没有,仅仅是把结果映射到一个list集合中时,仅仅需要用resulttype。
22. resultType和resultMap的总结:
resulttype:
作用:将查询结果按照sal列名,pojo属性名映射到一个pojo对象中
场合:常见一些记录的明细。比如商品明细,将关联信息全部显示在页面时,可直接适应resulttype将每一条记录映射到一个rojo对象中,在前端页面遍历list集合即可。
resultMap
作用:使用association和collection完成一对一和一对多高级映射。
Association
作用:将关联查询信息映射到一个pojo对象中
场合:比如查询订单和用户关联信息。为查询方便可以把订单信息映射到用户对象的pojo属性中。
Collection
作用:将关联信息映射到一个list中。
场合:比如查询模块权限范围下的信息。可将模块名称映射到list中。再将权限下的信息映射到对象模块中的list下。
23. 延迟加载
Association和collection有延迟加载的功能。
假如说你需要查询订单并且关联查询用户信息。则可以先查询商品订单,在需要时再去查询用户信息。把对用户信息的按需求去查询,就是延迟加载。
延迟加载:先查询简单的,即先从单表查询,再去从单表中关联查询。大大提高数据库性能。
1) Mapper.Xml
思路:定义连个statement语句。第一个:查询订单。第二个:查询用户信息。在查询订单的statement中使用association实现对第二个(用户信息)查询的延迟加载。
延迟加载的resultmap(使用association):
<resultMaptype="orders"id="lazy">
<!-- 对订单信息的配置 -->
<id/>
<result/>
<!-- 对用户信息实现延迟加载 -->
<associationproperty="user"javaType="User"select="指定延迟加载所需要执行的sql语句(statement的id)"column="两次查询关联查询的列">
</association>
</resultMap>
2) 延迟加载配置
Mybatis默认不开启延迟加载。需要在sqlmapconfig.xml用setting进行配置。
LazyLoadingEnabled: 全局性设置懒加载。如过为false。则全部相关信息都被初始化。默认false。
AggressiveLazyloading:当设置为true时,所有的懒加载对象可能被任何属性全部加载。否则每个属性按需加载。默认true。
<setting>
<settingname="LazyLoadingEnabled"value="true"/>
<Settingname="AggressiveLazyLoading"value="false"/>
</setting>
总之,使用延迟加载就是先去查询简单信息,再去查询关联信息。
24. 缓存
一级缓存是sqlsession缓存:操作数据库时,需要先创建一个sqlsession会话,sqlsession中有一个数据结构(hashmap)用于缓存数据,不同的sqlsession之间不影响。
二级缓存是mapper缓存:多个sqlsession去操作同一个mapper的sql语句。多个sqlsession去操作数据库得到的数据会存在二级缓存区域。即二级缓存是跨sqlsession的。
缓存中如果有,则不需要去数据库查找,提高系统性能。
25.一级缓存
工作原理(以按id查询为例):
Sqlsession写入
清空
读取
第一次发出查询请求,先去缓存区域看有没有,如果没有,则去数据库找,得到用户信息,存储在一级缓存中。第二次查询去缓存中直接存取。注意:如果两次之间有了commit,则会清空缓存中关于这个数条数据的信息。避免脏读。
26.二级缓存
工作原理:
写入
读取 清空
同理,如果另一个sqlsession进行提交,也会清空该二级缓存下的缓存。
二级缓存比一级缓存区域大。二级缓存可以跨Sqlsession。每个mapper(按照namespace分)有一个缓存区域。
前提:开启二级缓存。
在sqlmapconfig文件中开启:
<setting name=”cacheEnabled”value=”true”/>
在usermapper中开启:
<cache/>
应用场景:
适用于用户访问多,实时性不高的查询。或者耗时的sql语句时。设置刷新频率(flushInterval)为24h,30min等等。
局限性:
比如京东的商品信息,一发生变化,则需要立即被用户知道。假设有一个商品有了commit请求,则需要全部清空缓存。即对细粒度缓存不好。
27.Mybatis整合encache
使用分布缓存对缓存数据进行整合管理。Mybatis无法实现整合缓存,所以需要和其他缓存框架进行整合。实现cache接口。
配置xml文件:
<cache type=”使用的cache类型,默认使用perpetualCache”/>
要和encache整合,type配eneache的实现类。(先导包)
创建一个encache.Xml文件:
- MyBatis笔记
- Mybatis笔记
- mybatis笔记
- 【Mybatis笔记】
- mybatis笔记
- mybatis笔记
- mybatis笔记
- mybatis笔记
- mybatis笔记
- Mybatis笔记
- mybatis笔记
- MyBatis 笔记
- mybatis 笔记
- mybatis笔记
- MyBatis笔记
- Mybatis笔记
- Mybatis 笔记
- Mybatis笔记
- 数据库概念
- 为什么AI工程师成为当前薪资最高的技术岗位
- 围棋中的数学原理
- tomcat中存放含有中文的文件访问不到解决办法(设置Tomcat的UTF-8编码)
- 干货 | Elasticsearch 集群健康值红色终极解决方案
- Mybatis笔记
- Lougu
- 百度地图和高德地图的坐标转换
- docker配置zookeeper
- C++ 在继承中虚函数、纯虚函数、普通函数,三者的区别
- 数据库链接池模型实现--多线程(非线程池)版
- Spring 概述
- 设计模式之适配器模式
- Codeforces Round #444 (Div. 2)_D. Ratings and Reality Shows_模拟