Mybatis
Posted zys2019
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis相关的知识,希望对你有一定的参考价值。
1. 什么是mybatis
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
2. mybatis入门
2.1mybatis下载
mybaits的代码由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases
2.2工程搭建
第一步:创建java工程
第二步:加入需要的jar包
第三步:配置db.properties文件
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf-8 jdbc.username=root jdbc.password=123456
第四步:编写mybatyis配置文件SqlMapConfig.xml
为了看起来清晰,就把所有的配置文件放在一个新的文件夹中,所有在项目下新建一个文件夹config,把他设置为资源目录(classpath,src也是资源目录),然后新建一个SqlMapConfig.xml文件,编写如下配置,不要忘了包扫描:
<?xml version="1.0" encoding="uTF-8" ?> <!-- mybatis核心配置 --> <!-- 导入约束的路径 --> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!-- 配置信息 --> <configuration> <!-- 引入并加载外部文件 --> <properties resource="db.properties"></properties> <!-- 给类取别名 --> <typeAliases> <!-- 单独取别名 <typeAlias type="com.entity.Admin" alias="admin"></typeAlias> --> <!-- 使用包扫描方式取别名 --> <package name="com.entity"/> </typeAliases> <!-- 环境配置的集合 --> <environments default="mysql"> <environment id="mysql"> <!-- 事务管理:type指定事务的管理方式,jdbc:交给jdbc管理,MANAGED:被管理 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据库配置:type是否使用连接池,POOLED:使用连接池,UNPOOLED:不使用连接池 --> <dataSource type="POOLED"> <property name="driver" value="$jdbc.driver" /> <property name="url" value="$jdbc.url" /> <property name="username" value="$jdbc.username" /> <property name="password" value="$jdbc.password" /> </dataSource> </environment> </environments> <!-- 加载映射文件 --> <mappers> <!-- 单独加载映射文件 <mapper resource="adminMapper.xml"></mapper> --> <!-- 加载整个包 --> <package name="com.dao"/> </mappers> </configuration>
第五步:创建po实体类
ackage com.entity; public class User private int id; private String username; private String password; //get和set,toString方法在此略,使用时需要生成
第六步:编写mybatyis映射文件
新建一个userDao.xml文件,这个文件要和下面要创建的接口类放在同一个目录。编写如下配置:
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.dao.UserDao"> <!--查询所有信息 id是这个select的唯一标识 resultType是返回类型 parameterType是参数类型 --> <select id="findAll" resultType="com.dao.User"> select * from user </select> </mapper>
第七步:创建一个接口
package com.dao; import com.entity.User; import java.util.List; public interface UserDao List<User> findAll();
接口中的方法要和select的id相同,其他雷同,一定不要忘了在接口中写对应的方法。
第八步:编写测试类
在使用系统的测试类时,可以在测试目录下新建一个另类,不能以Test命名,然后写@Test导入junit的类,然后写方法可以直接测试,不需要写主方法:
package test; import com.entity.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.log4j.Logger; import org.junit.Test; import java.io.IOException; import java.io.Reader; import java.util.List; public class Mybatis02 @Test public void findAll() throws IOException //加载核心配置文件 Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml"); //创建SessionFactory SqlSessionFactory build= new SqlSessionFactoryBuilder().build(reader); //创建一个session对象 SqlSession session = build.openSession(); //操作映射 List<User> list = session.selectList("com.dao.UserDao.findAll"); System.out.println(list);
2.3自定义文件
在这里就自定义一个xml文件,使用起来方便点。
2.4配置日志文件
新建一个log4j.properties文件,配置如下:
### 设置当前日志级别 ### log4j.rootLogger = debug,stdout,D,E ### 输出信息到控制抬 ### log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = [%-5p] %dyyyy-MM-dd HH:mm:ss,SSS method:%l%n%m%n ### 输出DEBUG 级别以上的日志到=E://logs/log.log ### log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = E://logs/log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-dyyyy-MM-dd HH:mm:ss [ %t:%r ] - [ %p ] %m%n ### 输出ERROR 级别以上的日志到=E://logs/error.log ### log4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File =E://logs/error.log log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-dyyyy-MM-dd HH:mm:ss [ %t:%r ] - [ %p ] %m%n
配置之后导入log4j的相关jar包,创建日志对象,把信息写到日志文件中,尽量每天一个日志文件,把debug和error的日志写到日志文件中,方便查阅:
//创建日志对象 Logger logger=Logger.getLogger(Mybatis02.class);
会在控制台输出一些日志,这句代码放在类中方法之前,debug信息会自动写到文件中,error信息要在发生异常的地方手动添加。
catch (IOException e) //把错误信息写到日志文件 logger.error(e.getMessage()); e.printStackTrace();
3. mybatis的增删改查
这里有多个方法,所以进行代码优化:
public SqlSessionFactory build=null; //这个在方法加载的时候就会初始化 @Before public void before() Logger logger=Logger.getLogger(Mybatis02.class); Reader reader=null; //加载核心配置文件 try reader= Resources.getResourceAsReader("SqlMapConfig.xml"); //创建SessionFactory build = new SqlSessionFactoryBuilder().build(reader); catch (IOException e) e.printStackTrace();
3.1根据id查询
<!-- 如果参数是简单数据类型,可以省略 --> <select id="findById" parameterType="int" resultType="User"> select * from user where id=#id </select>
接口中的方法比较简单,这里就不展示,不要忘了编写对应的方法
@Test public void findById() SqlSession session = build.openSession(); User user=session.selectOne("com.dao.UserDao.findById",14); System.out.println(user);
com.dao.UserDao.findById代表的是接口中的方法,后面接参数
3.2查询所有
<select id="findAll" resultType="com.entity.User"> select * from user </select>
@Test public void findAll() throws IOException //创建一个session对象 SqlSession session = build.openSession(); //操作映射 List<User> list = session.selectList("com.dao.UserDao.findAll"); System.out.println(list);
3.3根据用户名和密码查询
<select id="findByNmAndPwd" parameterType="User" resultType="User"> select * from user where username=#username and password=#password </select>
# 里面的参数一定要和对象中的属性保持一致
@Test public void findByNmAndPwd() SqlSession session = build.openSession(); User user=new User(); user.setUsername("方启豪"); user.setPassword("123"); User user2 = session.selectOne("com.dao.UserDao.findByNmAndPwd", user); System.out.println(user2);
3.4添加用户
<insert id="addUser" parameterType="User"> insert into user values(null,#username,#password) </insert>
增加删除修改一定要提交事务
@Test public void addUser() SqlSession session = build.openSession(); User user=new User(); user.setUsername("方启豪5号"); user.setPassword("12315"); int i = session.insert("com.dao.UserDao.addUser", user); session.commit();//提交事务 System.out.println(i);
3.5修改用户
<update id="updateUser" parameterType="com.entity.User"> update user set username=#username,password=#password where id=#id </update>
@Test public void updateUser() SqlSession session = build.openSession(); User user=new User(); user.setId(9); user.setUsername("方启豪2号"); user.setPassword("123"); session.insert("com.dao.UserDao.updateUser", user); session.commit();
3.6删除用户
<delete id="deleteUser"> delete from user where id=#value </delete>
@Test public void deleteUser() SqlSession session = build.openSession(); session.delete("com.dao.UserDao.deleteUser", 9); session.commit();
3.7模糊查询:一个条件
使用$,并且括号里面只能写value,这里参数是简单数据类型
<!-- 模糊查询:一个条件,使用$,并且括号里面只能写value -->
<select id="findByLikeOne" resultType="User">
select * from user where username like ‘%$value%‘
</select>
@Test public void findByLikeOne() SqlSession session = build.openSession(); List<User> list=session.selectList("com.dao.UserDao.findByLikeOne", "启"); System.out.println(list);
3.8模糊查询:多个条件
使用$,并且括号里面要与对象的属性相同
<!-- 模糊查询:多个条件,使用$,并且括号里面要与对象的属性相同 -->
<select id="findByLikeMore" parameterType="User" resultType="User">
select * from user where username like ‘%$username%‘ and password like ‘%$password%‘
</select>
@Test public void findByLikeMore() SqlSession session = build.openSession(); User user=new User(); user.setUsername("钟"); user.setPassword("1"); List<User> list=session.selectList("com.dao.UserDao.findByLikeMore", user); System.out.println(list);
4. 小结
4.1#和$的区别
#表示一个占位符号,通过#可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#可以有效防止sql注入。 #可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#括号中可以是value或其它名称。
$表示拼接sql串,通过$可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, $可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,$括号中只能是value。
4.2parameterType和resultType
parameterType:指定输入参数类型
resultType:指定输出结果类型
4.3selectOne和selectList
selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:
org.apache.ibatis.exceptions.TooManyResultsException
selectList可以查询一条或多条记录
4.4mybatis与hibernate的区别
Mybatis是对jdbc的封装,注重的是sql语句,是一种轻量级的半自动框架,适用于敏捷开发,原理是反射
Hibernate注重映射关系,是一种重量级的全自动的框架。
4.5取别名typeAliases
mybatis支持别名:
别名 |
映射的类型 |
_byte |
byte |
_long |
long |
_short |
short |
_int |
int |
_integer |
int |
_double |
double |
_float |
float |
_boolean |
boolean |
string |
String |
byte |
Byte |
long |
Long |
short |
Short |
int |
Integer |
integer |
Integer |
double |
Double |
float |
Float |
boolean |
Boolean |
date |
Date |
decimal |
BigDecimal |
bigdecimal |
BigDecimal |
map |
Map |
自定义别名:
在SqlMapConfig.xml中配置:
<typeAliases> <!-- 单个别名定义 --> <typeAlias alias="user" type="com.entity.User"/> <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) --> <package name="com.entity"/> <package name="其它包"/> </typeAliases>
4.6mappers(映射器)
Mapper配置的几种方法:
第一种:<mapper resource=" " />使用相对于类路径的资源
如:<mapper resource="sqlmap/User.xml" />
第二种:<mapper class=" " />使用mapper接口类路径
如:<mapper class="com.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
第三种:<package name=""/>注册指定包下的所有mapper接口
如:<package name="com.mapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<!-- 加载映射文件 --> <mappers> <!-- 单独加载映射文件 <mapper resource="adminMapper.xml"></mapper> --> <!-- 加载整个包 --> <package name="com.dao"/> </mappers>
5. dao开发
5.1原始dao开发
原始Dao开发方法需要程序员编写Dao接口和Dao实现类。
1、编写映射文件:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="test"> <!-- 根据id获取用户信息 --> <select id="findUserById" parameterType="int" resultType="com.hp.entity.User"> select * from user where id = #id </select> <!-- 根据name模糊查询 --> <select id="findLikeName" parameterType="java.lang.String" resultType="com.hp.entity.User"> select * from user where username like ‘%$value%‘ </select> <!-- 添加用户 --> <insert id="insertUser" parameterType="com.hp.entity.User"> <!-- 获取生成的主键的值,返回到user对象中 --> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> select LAST_INSERT_ID() </selectKey> insert into user(username,password) values(#username,#password) </insert> </mapper>
2、编写dao文件:
接口:
public interface IUserDao User findUserById(int id); List<User> findUserLikeName(String name); void addUser(User user);
实现类:
public class UserDaoImpl implements IUserDao SqlSessionFactory factory = null; public UserDaoImpl(SqlSessionFactory factory) this.factory = factory; @Override public User findUserById(int id) SqlSession session = factory.openSession(); User user = session.selectOne("test.findById", id); session.close(); return user; @Override public List<User> findUserLikeName(String name) SqlSession session = factory.openSession(); List<User> list = session.selectList("test.findLikeName", name); session.close(); return list; @Override public void addUser(User user) SqlSession session = factory.openSession(); session.insert("test.insertUser", user); session.commit(); session.close();
3、测试:
public class MybatisTest SqlSessionFactory factory = null; @Before public void createFactory() throws IOException InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(is); @Test public void test7() IUserDao dao = new UserDaoImpl(factory); User user = dao.findUserById(4); System.out.println(user); @Test public void test8() IUserDao dao = new UserDaoImpl(factory); List<User> list = dao.findUserLikeName("李"); System.out.println(list); @Test public void test9() IUserDao dao = new UserDaoImpl(factory); User user = new User(); user.setPassword("2222"); user.setUsername("张三"); dao.addUser(user);
5.2Mapper动态代理方式开发Dao
只需要程序员编写Mapper接口,非常适用于mybatis,Mapper接口开发需要遵循以下规范:
1、Mapper.xml文件中的namespace与mapper接口的路径相同。
2、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
配置文件及测试在入门里已经进行了,这里就省略了。动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
//mapper动态代理模板
@Test public void testInsert() SqlSession sqlSession = sqlSessionFactory.openSession(); EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class); Emp emp = new Emp(); emp.setEname("admin"); emp.setJob("admin"); int flag = 0; try flag = empMapper.insertEmp(emp); finally sqlSession.commit(); sqlSession.close(); if(flag == 1) System.out.println("自增主键值:"+emp.getEmpno());
6. lombok的使用
第一步:安装插件
第二步:导入jar包
第三步:在实体类中使用注解即可
删除User类中的方法,只保留属性,添加注解@Setter,@Getter,那么就可以在其他类中使用get和set方法,这样就简化了代码:
package com.entity; import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString public class User private int id; private String username; private String password;
这样注解还不能生效,还要一点配置:
Lombok注解:
注解 |
说明 |
@Setter |
注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法 |
@Getter |
使用方法同上,区别在于生成的是getter方法 |
@ToString |
注解在类,添加toString方法 |
@EqualsAndHashCode |
注解在类,生成hashCode和equals方法 |
@NoArgsConstructor |
注解在类,生成无参的构造方法 |
@RequiredArgsConstructor |
注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段 |
@AllArgsConstructor |
注解在类,生成包含类中所有字段的构造方法 |
@Data |
注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法 |
@Slf4j |
注解在类,生成log变量,严格意义来说是常量 |
7.resultMap与parameterMap
7.1复杂条件的查询举例
当参数不属于同一个对象时,使用简单的查询非常麻烦,那么可以把一个对象作为另一个对象的属性结合使用:
ackage com.entity; public class Person private String username; package com.entity; public class People private int age;
把上面的两个对象作为属性给PVo,那么他使用起来就比较方便了。
package com.entity; public class PVo private People people; private Person person;
一个简单的插入语句:
<insert id="Pvo" parameterType="PVo"> insert into user valuesnull,#person.username,#people.password) </insert>
7.2resultMap的使用
当查询的结果不仅仅是一个对象的全部属性时,如果再创建一个对象来封装数据就显得格外的麻烦,那么可以使用resultMap来对属性进行重定义,这样就可以直接返回一个map的结果。
复杂查询:查询用户的id,用户名以及所对应的成绩的id和具体成绩(一对一)
数据库信息
<!-- 复杂查询:查询用户的id,用户名以及所对应的成绩的id和具体成绩 --> <!--定义表数据与组合类的映射关系,id是唯一标识,type是类型--> <resultMap id="userAndScore" type="User"> <!--id是主键映射,result是非主键映射,column是数据库中的列名,properties是对象的属性名--> <!--如果多个表中的属性名一样,要注意区分,如这里的id--> <id column="uid" property="id"></id> <result column="username" property="username"></result> <result column="password" property="password"></result> <!--association对属性是对象的变量的深入映射,适用于一对一的关系--> <association property="score" javaType="Score"> <id column="sid" property="id"></id> <result column="grade" property="grade"></result> <result column="u_id" property="u_id"></result> </association> </resultMap> <!--这里的返回类型必须是map集合--> <select id="findUserAndScore" resultMap="userAndScore"> select user.id uid, username,score.id sid,grade from user,score where user.id=score.u_id </select>
User类
package com.entity; import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString public class User private int id; private String username; private String password; //score的类型是对象 private Score score; Score类 package com.entity; import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString public class Score private int id; private double grade; private int u_id;
测试方法
@Test public void findUserAndScore() SqlSession session = build.openSession(); List<User> list=session.selectList("com.dao.UserDao.findUserAndScore"); System.out.println(list);
复杂查询:查询用户的id,用户名以及所对应的成绩的id和具体成绩(一对多)
数据库信息
<resultMap id="userAndScore" type="User"> <id column="uid" property="id"></id> <result column="username" property="username"></result> <result column="password" property="password"></result> <!--collection对属性是对象的变量的深入映射,适用于一对多的关系--> <!--javaType指属性是什么类型,ofType指集合中装的什么类型--> <collection property="scores" javaType="java.util.List" ofType="Score"> <id column="sid" property="id"></id> <result column="grade" property="grade"></result> <result column="u_id" property="u_id"></result> </collection> </resultMap> <!--这里的返回类型必须是map集合--> <select id="findUserAndScore" resultMap="userAndScore"> select user.id uid, username,score.id sid,grade from user,score where user.id=score.u_id </select>
User类如下,score和测试方法没有变。
8.动态sql
8.1if标签
当标签里面test的内容为true时才会去执行if里面的语句
查询:根据id查询,如果id不为空就根据id查询,否则就让id为0进行查询
<select id="findById" resultType="User"> select * from user <if test="value!=null"> where id=#value </if> <if test="value==null"> where id=0 </if> </select>
8.2where标签
where会自动去识别,当sql语句中已经有where那么它会直接拼接where里面的内容,如果没有就直接使用;另外where里面的and也类似,如果已经有where就使用and,如果没有就舍弃第一个and。
查询:当id不为空就根据id查询,否则就查询所有
<select id="findById" resultType="User"> select * from user where 1=1 <if test="value!=null"> <where> and id=#value </where> </if> </select>
8.3foreach标签
用来遍历集合等,用于传入参数是多个相同类型的查询,可以使用在in,limit,between。。。
查询:传入多个id查询用户信息
<select id="findByIn" parameterType="java.util.List" resultType="User"> select * from user <!--如果传入参数是list类型,必须使用list获取,并且使用and--> <if test="list.size()>0 and list!=null"> where id in <!--collection要遍历的集合,open开始的符号,close结束的符号,separator分隔符--> <!--index是索引,item是每一条内容,这里是list.get(i)--> <foreach collection="list" open="(" separator="," close=")" index="i" item="item" > #item </foreach> </if> </select>
@Test public void findByIn() SqlSession session = build.openSession(); List<Integer> list=new ArrayList<Integer>(); list.add(1); list.add(14); list.add(22); List<User> list1=session.selectList("com.dao.UserDao.findByIn",list); System.out.println(list1);
8.4sql片段
将会重复使用的sql语句抽取出来,需要使用的地方直接引入
<!--sql片段--> <sql id="select"> select * from user </sql> <select id="findById" resultType="User"> <!--引入sql片段--> <include refid="select"/> where is=#value </select>
9.延迟加载
需要查询关联信息时,我们先查询一部分信息,再关联查询关联信息,叫延迟加载。主要通过resultMap实现延迟加载。延迟加载需要导入cglib以及asm的jar包。
9.1打开延时加载的开关
在SqlMapConfig.xml中配置:
<settings> <!-- 延迟加载开关 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 当设置为true的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载--> <setting name="aggressiveLazyLoading" value="false"/> </settings>
9.2写sql语句
根据用户名和密码查询出id,然后再根据id查询对应的成绩
User类和Score类在此略,可参考上面7.2复杂查询中一对多查询的定义
9.3测试
@Test public void findUserAndScore2() SqlSession session = build.openSession(); User user=new User(); user.setUsername("钟玉石"); user.setPassword("123"); List<User> list=session.selectList("com.dao.UserDao.findUserAndScore2",user); System.out.println(list.get(0).getId()); System.out.println("-------------"); System.out.println(list.get(0).getScores().get(0));
查询之后可以看到先执行一次查询,然后再去执行后面的查询,并没有一次性查询出结果。
9. Mybatis缓存
将从数据库查询的数据存储到内存中缓存起来,这样就不用从数据库中查询数据而从缓存中查询,提高查询的速度,减少对数据库的访问。
10.1一级缓存
一级缓存使用
一级缓存:当执行两条相同的查询语句时,mybatis只执行一次查询,map中存储了sql执行查询的结果集。
一级缓存是session级别的缓存,当执行增删改中的任何一个操作,缓存就会清空。
一级缓存查询:
@Test public void findById() SqlSession session = build.openSession(); User user=session.selectOne("com.dao.UserDao.findById",14); System.out.println(user); System.out.println("----------"); User user2=session.selectOne("com.dao.UserDao.findById",14); System.out.println(user2);
查询结果如下
一级缓存查询中执行增加操作:
@Test public void findById() SqlSession session = build.openSession(); User user=session.selectOne("com.dao.UserDao.findById",14); System.out.println(user); User user3=new User(); user3.setUsername("方启豪6号"); user3.setPassword("12315"); session.insert("com.dao.UserDao.addUser", user3); session.commit();//提交事务 System.out.println("----------"); User user2=session.selectOne("com.dao.UserDao.findById",14); System.out.println(user2);
只要清空了session,那么就清除了缓存,就需要重新查询。也可以手动清空session,语句是
一级缓存原理
第一次查询先去缓存中找是否有缓存数据,发现没有,查询数据库,将查询到的数据写入sqlsession的一级缓存区域。
第二次查询先去缓存中找是否有缓存数据,发现有,直接从缓存区域中取出数据返回。如果执行sqlsession的添加、修改、删除等操作,会执行commit,最终会清空缓存。
10.2二级缓存
二级缓存是mapper(命名空间)级别的缓存,默认是开启的,只有session提交或关闭时才能把结果提交到二级缓存中,当执行增删改中的任何一个操作,缓存就会清空。
二级缓存的使用
二级缓存的使用需要进行配置:
第一步:在SqlMapConfig.xml的settings中加一行代码:
<!--开启并标识二级缓存--> <setting name="cacheEnabled" value="true"/>
第二步:在userDao.xml中加一行代码:
第三步:User类要实现Serializable接口
二级缓存测试
@Test public void findById() SqlSession session = build.openSession(); SqlSession session2 = build.openSession(); UserDao mapper=session.getMapper(UserDao.class); UserDao mapper2=session2.getMapper(UserDao.class); User user=mapper.findById(14); System.out.println(user); session.close(); System.out.println("----------"); User user2=mapper2.findById(14); System.out.println(user2); session2.close();
查询结果
二级缓存原理
不同的sqlsession都要调用mapper下的sql语句发起数据库请求。sqlsession1执行UserMapper下的查询用户请求先从二级缓存中查找有没有数据,如果没有就从数据库中查询,并且将查询到数据存储二级缓存中。
sqlsession2执行UserMapper下的同一个查询用户请求,先从二级缓存中查找有没有数据,如果有就从二级缓存中查询数据,返回。
如果有一个sqlsession3执行UserMapper下添加、修改、删除语句,执行commit操作后,将UserMapper下的所有缓存数据全部清空。
9. Mybatis注解
11.1@Param参数传入
当参数少于4个的时候可以使用注解参数的传入,如果参数过多,就使用原始pojo的方式
UserDao类:
//使用注解Param传递参数,引号里面的参数是要使用的参数,如#username User findByNmAndPwd(@Param("username")String username,@Param("password")String password);
userDao.xml中sql:
<select id="findByNmAndPwd" resultType="User"> select * from user where username=#username and password=#password </select>
测试类:
@Test public void findByNmAndPwd() SqlSession session = build.openSession(); UserDao mapper = session.getMapper(UserDao.class); User user=mapper.findByNmAndPwd("方启豪","123"); System.out.println(user);
11.2@Insert @Update @Delete
此注解不需要userDao.xml文件,这三个用法雷同,以update为例:
UserDao类:
//这里参数传的是一个对象 @Update("update user set username=#user.username, password=#user.password where id=#user.id") void updateUser(@Param("user")User user);
测试类:
@Test public void updateUser() SqlSession session = build.openSession(); UserDao mapper = session.getMapper(UserDao.class); User user=new User(); user.setId(14); user.setUsername("方启豪222号"); user.setPassword("123"); mapper.updateUser(user); session.commit();
11.3@Select
此注解不需要userDao.xml文件
UserDao类:
@Select("select * from user where id=#id") User findById(@Param("id") Integer id);
测试类:
Test public void findById() SqlSession session = build.openSession(); UserDao mapper=session.getMapper(UserDao.class); User user=mapper.findById(14); System.out.println(user);
以上是关于Mybatis的主要内容,如果未能解决你的问题,请参考以下文章