一、MyBatis原理
1、核心
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
2、作用域和生命周期
-
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
-
SqlSessionFactory
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
-
SqlSession
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。返回一个响应后,就关闭它。 这个关闭操作很重要
-
映射器实例
映射器是一些绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的。虽然从技术层面上来讲,任何映射器实例的最大作用域与请求它们的 SqlSession 相同。但方法作用域才是映射器实例的最合适的作用域。 也就是说,映射器实例应该在调用它们的方法中被获取,使用完毕之后即可丢弃。 映射器实例并不需要被显式地关闭。尽管在整个请求作用域保留映射器实例不会有什么问题,但是你很快会发现,在这个作用域上管理太多像 SqlSession 的资源会让你忙不过来。 因此,最好将映射器放在方法作用域内。
二、构建一个简单的MyBatis项目
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zseAjcsX-1609828347456)(C:\Users\张聪\AppData\Roaming\Typora\typora-user-images\1608530853124.png)]
1、创建数据库表
2、导入mybatis相关jar包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
<dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
<dependency>
3、编写mybatis-config核心配置文件
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器
XML 头部的声明,它用来验证 XML 文档的正确性。environment 元素体中包含了事务管理和连接池的配置。mappers 元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--数据源配置第一种方法直接配置-->
<!--
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/demo?useSSL = true&useUnicode = true&characterEnconding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments> -->
<!--数据源配置第二种方法直接配置-->
<!--在src下新建一个properties文件,里面填写数据源参数,然后通过<properties>标签引入进来-->
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/zc/data/mapper.xml"/>
</mappers>
</configuration>
4、编写mybatis工具类
public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try{
//通过MyBatis下的Resources工具类获得一个输入流,来获取SqlSessionFactory对象
String resource = "com/zc/data/mabatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch(Exception e){
e.printStackTrace();
}
}
//获取sqlsession连接,SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}
5、创建实体类
public class Hero {
private String name;
private int age;
private String position;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
@Override
public String toString() {
return "Hero [name=" + name + ", age=" + age + ", position=" + position + ", getName()=" + getName()
+ ", getAge()=" + getAge() + ", getPosition()=" + getPosition() + "]";
}
}
6、编写mapper接口类
public interface HeroMapper {
//查询所有
List<Hero> selectAll();
}
7、编写mapper.xml配置文件
<?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">
<!--这里是通过命名空间namespace进行映射查找的-->
<mapper namespace="com.zc.mapper.HeroMapper">
<select id="selectAll" resultType="com.zc.entity.Hero">
select * from hero
</select>
</mapper>
8、测试类
public class Test01 {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtil.getSession();
HeroMapper mapper = sqlSession.getMapper(HeroMapper.class);
List<Hero> heros = mapper.selectAll();
for (Hero hero : heros) {
System.out.println(hero);
}
sqlSession.close();
}
}
三、MyBatis的CURD
-
接口类
public interface HeroMapper { //查询所有 List<Hero> selectAll(); //根据一个条件查 Hero selectByName(String name); //根据多个条件查,参数前要加上@Param属性,这样映射时就以param中的为准了 Hero selectByNameAndPositon1(String name,String position);//不可行 Hero selectByNameAndPositon2(@Param("name")String nameString,@Param("position")String position); Hero selectByNameAndPositon3(Map map); //增加一个用户 int addHero(Hero hero); //修改一个用户 int updateHero(Hero hero); //删除一个用户 int deleteHero(@Param("name")String name); }
-
mapper.xml配置文件
<?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="com.zc.mapper.HeroMapper"> <select id="selectAll" resultType="com.zc.entity.Hero"> select * from hero </select> <select id="selectByName" resultType="com.zc.entity.Hero"> select * from hero where name=#{name} </select> <select id="selectByNameAndPositon1" resultType="com.zc.entity.Hero"> select * from hero where name=#{name} and position = #{position} </select> <select id="selectByNameAndPositon2" resultType="com.zc.entity.Hero"> select * from hero where name=#{name} and position = #{position} </select> <select id="selectByNameAndPositon3" resultType="com.zc.entity.Hero"> select * from hero where name=#{name} and position = #{position} </select> <!-- 增加 --> <insert id="addHero"> insert into hero (name,age,position) values (#{name},#{age},#{position}) </insert> <!-- 修改 --> <update id="updateHero"> update hero set age=#{age} where name=#{name} </update> <!-- 删除 --> <delete id="deleteHero"> delete from hero where name=#{name} </delete> </mapper>
-
测试代码
public class Test01 { public static void main(String[] args) { SqlSession sqlSession = MybatisUtil.getSession(); HeroMapper mapper = sqlSession.getMapper(HeroMapper.class); /** *查询所有 */ // List<Hero> heros = mapper.selectAll(); // for (Hero hero : heros) { // System.out.println(hero); // } /** *按一个条件进行查询 */ // Hero hero = mapper.selectByName("韩信"); // System.out.println(hero); // //第二种写法 // Hero hero2 = (Hero)MybatisUtil.getSession().selectOne( "com.zc.mapper.HeroMapper.selectByName", "韩信"); // System.out.println(hero2); /** * 按多个条件进行查询 */ //使用@Param属性 // Hero hero = mapper.selectByNameAndPositon2("李白", "刺客"); // System.out.println(hero); //使用Map作为参数传值 // Map map = new HashMap<String , String>(); // map.put("name", "李白"); // map.put("position", "刺客"); // Hero hero = mapper.selectByNameAndPositon3(map); // System.out.println(hero); /** * 新增 */ // Hero hero = new Hero(); // hero.setAge(25); // hero.setName("澜朋友"); // hero.setPosition("刺客"); // int index= mapper.addHero(hero); // System.out.println(index); // sqlSession.commit();//提交事务,不执行的话不会提交到数据库。增删改都要提交事务 /** * 修改 */ // Hero hero = new Hero(); // hero.setAge(100); // hero.setName("澜朋友"); // hero.setPosition("刺客"); // int index = mapper.updateHero(hero); // System.out.println(index); // sqlSession.commit(); /** * 删除 */ int index = mapper.deleteHero("聪聪"); System.out.println(index); sqlSession.commit(); sqlSession.close(); } }
四、ResultMap及分页
1、当数据库中的表字段与实体类中属性字段不一致时,可以通过ResultMap来进行映射。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uPqCTERz-1609828347460)(C:\Users\张聪\AppData\Roaming\Typora\typora-user-images\1609314184413.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JxBxfpa3-1609828347463)(C:\Users\张聪\AppData\Roaming\Typora\typora-user-images\1609314226745.png)]
//public class Test01 {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtil.getSession();
HeroMapper mapper = sqlSession.getMapper(HeroMapper.class);
Hero hero = (Hero)mapper.selectHeroByAge(25);
System.out.println(hero);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-afWdMXLg-1609828347468)(C:\Users\张聪\AppData\Roaming\Typora\typora-user-images\1609314295641.png)]
查询出的名字为null==>原因:mybati会根据查询的列名去对应的实体类中查找相应列名的set方法设值,找不到,所以返回null。
解决办法:
1、为不一样的列名指定别名,别名与实体类的属性字段一致
<mapper namespace="com.zc.mapper.HeroMapper">
<select id="selectHeroByAge" resultType="com.zc.entity.Hero">
select name as heroname,age,position from hero where age = #{age}
</select>
</mapper
2、使用结果映射集–ResultMap
属性 | 描述 |
---|---|
property | 需要映射到JavaBean的属性名称 |
column | 数据表的列名或者标签别名 |
javaType | 一个完整的类名或类型别名 |
jdbcType | 数据表支持的类型列表。该属性只在insert、update、delete时针对允许空的列有用。 |
typeHandler | 使用这个属性可以覆写类型处理器。可以是一个完整类名,也可以时一个类型别名。 |
<mapper namespace="com.zc.mapper.HeroMapper">
<!--结果映射集-->
<resultMap id="hero" type="com.zc.entity.Hero">
<!--主键-->
<!--<id column="" property></id>-->
<!--column对应数据库,property对应实体类-->
<result column="name" property="heroname"/>
<result column="age" property="age"/>
<result column="property" property="property"/>
</resultMap>
<!--结构集使用resultMap-->
<select id="selectHeroByAge" resultMap="hero">
select name,age,position from hero where age = #{age}
</select>
</mapper>
2、分页
#从第startindex开始,每次查pagesize条
select * from hero limit startindex,pagesize;
public interface HeroMapper {
List<Hero> selectpage(Map map);
}
<!-- 分页查询 -->
<select id="selectpage" resultType="com.zc.entity.Hero">
select * from hero limit #{currentpage},#{pagesize}
</select>
public class Test01 {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtil.getSession();
HeroMapper mapper = sqlSession.getMapper(HeroMapper.class);
Map map = new HashMap();
int currentpage=1;//当前页
int pagesize=2;//每页显示记录数
map.put("currentpage", currentpage);
map.put("pagesize", pagesize);
List<Hero> list = mapper.selectpage(map);
for (Hero hero : list) {
System.out.println(hero);
}
sqlSession.close();
}
}
/**
Hero [name=null, age=50, position=刺客, getName()=null, getAge()=50, getPosition()=刺客]
Hero [name=null, age=25, position=战士, getName()=null, getAge()=25, getPosition()=战士]
*/
五、注解
1、sql类型
- @select()
- @update()
- @insert()
- @delete()
利用注解开发就不需要mapper.xml映射文件了
public interface HeroMapper {
@Select("select * from hero")
List<Hero> selectHeros();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--
<mappers>
<mapper resource="com/zc/data/mapper.xml"/>
</mappers>
-->
<!--mapper不再时mapper.xml文件-->
<mappers>
<mapper class="com.zc.mapper.HeroMapper"/>
</mappers>
</configuration>
public class Test01 {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtil.getSession();
HeroMapper mapper = sqlSession.getMapper(HeroMapper.class);
List<Hero> list = mapper.selectHeros();
for (Hero hero : list) {
System.out.println(hero);
}
sqlSession.close();
}
}
六、一对多与多对一处理
数据库案例
//创建老师表
create table teacher(
id int(10) not null,
name varchar(30) default null,
primary key(`id`)
);
insert into teacher(`id`,`name`) values(1,'张老师');
insert into teacher(`id`,`name`) values(2,'夏老师');
//创建学生表
create table student(
id int(10) not null,
name varchar(30) default null,
tid int(10) default null,
primary key(`id`),
key `fktid`(`tid`),
constraint `fktid` foreign key(`tid`)
references `teacher`(`id`)
);
insert into student(id,name,tid) values (1,'聪聪',1);
insert into student(id,name,tid) values (2,'小垃圾',1);
insert into student(id,name,tid) values (3,'小肚子',1);
//查询所有学生对应的老师
select distinct t.name from teacher t join student s on t.id = s.tid;
select s.name,t.name from student s,teacher t where s.tid = t.id;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LmULo0ZN-1609828347471)(C:\Users\张聪\AppData\Roaming\Typora\typora-user-images\1609400661473.png)]
多对一(多个学生对应一个老师–association关联属性)
按查询嵌套处理
//实体类中定义了老师属性字段,同时原来的属性不可少,否则会报错属性字段匹配不上
package com.zc.entity;
public class Student {
int id;
String name;
int tid;
Teacher teacher;
public Student(int id, String name, int tid, Teacher teacher) {
super();
this.id = id;
this.name = name;
this.tid = tid;
this.teacher = teacher;
}
public Student(int id, String name, int tid) {
super();
this.id = id;
this.name = name;
this.tid = tid;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getTid() {
return tid;
}
public void setTid(int tid) {
this.tid = tid;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", tid=" + tid + ", teacher=" + teacher + "]";
}
}
public interface StudentMapper {
public List<Student> getStudents();
}
<?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="com.zc.mapper.StudentMapper">
<select id="getStudents" resultMap="StudentTeacher">
select * from student
</select>
<!--association关联属性,
type:表示被转换的对象,本文中本来查询的结果集类型应为Student,即被转换的对象为Student
property:指的是实体类中定义的转换的属性字段
column:指的是转换的属性字段对象在多对一中多的表中对应的列名字段--这里指老师在学生表中对应的字 段。
javaType:指的是property对应的对象类型-->
<resultMap id="StudentTeacher" type="com.zc.entity.Student">
<association property="teacher" column="tid" javaType="com.zc.entity.Teacher" select="getTeacher">
</association>
</resultMap>
<select id="getTeacher" resultType="com.zc.entity.Teacher">
select * from teacher where id=#{id}
</select>
</mapper>
package com.zc.test;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import com.zc.entity.Student;
import com.zc.mapper.StudentMapper;
import com.zc.util.MybatisUtil;
public class Test01 {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtil.getSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> list = mapper.getStudents();
for (Student student : list) {
System.out.println("学生:"+student.getName()+",老师:"+student.getTeacher().getName());
}
sqlSession.close();
}
}
/**
*学生:聪聪,老师:张老师
*学生:小垃圾,老师:张老师
*学生:小肚子,老师:夏老师
*/
按结果集映射
<?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="com.zc.mapper.StudentMapper">
<select id="getStudents" resultMap="StudentTeacher">
select s.id sid,t.name tname from student s,teacher t where s.tid = t.id
</select>
<resultMap id="StudentTeacher" type="com.zc.entity.Student">
<id property="id" column="sid"></id>
<association property="teacher" javaType="com.zc.entity.Teacher">
<result property="name" column="tname"></result>
</association>
</resultMap>
</mapper>
sql查询实体类中必须要有与之对应数量类型一直的构造方法
一对多(一个老师对应多个学生)
按查询嵌套处理
//一个老师对应多个学生--老师的实体类中创建学生对象的集合
public class Teacher {
int id;
String name;
List<Student> students;
public Teacher(int id, String name, List<Student> students) {
super();
this.id = id;
this.name = name;
this.students = students;
}
public Teacher(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + ", students=" + students + "]";
}
}
public interface TeacherMapper {
Teacher getTeacher(int id);
}
<?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="com.zc.mapper.TeacherMapper">
<select id="getTeacher" resultMap="TeacherStudent">
select * from teacher where id=#{id};
</select>
<!--type:指的是被转换的对象,这里指老师-->
<resultMap id="TeacherStudent" type="com.zc.entity.Teacher">
<!--一对多查询出的集合用collection,其中students对应实体类中的创建的学生集合对象,
property:指的是在实体类中除了表对应字段属性外,多定义的字段属性
column:这里个人理解是两个表中关联字段在被转换对象表中对应的列名
javaType是用来指定pojo中属性的类型,即实体类中定义属性字段的类型,
ofType指定的是映射到list集合属性中的对象类型-->
<collection property="students" column="id" javaType="ArrayList" ofType="com.zc.entity.Student" select="getStudent" >
</collection>
</resultMap>
<select id="getStudent" resultType="com.zc.entity.Student">
select * from student where tid=#{id}
</select>
</mapper>
public class Test01 {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtil.getSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
List<Student> list = teacher.getStudents();
for (Student student : list) {
System.out.println("老师:"+teacher.getName()+",学生:"+student.getName());
}
/**
*老师:张老师,学生:聪聪
*老师:张老师,学生:小垃圾
*/
sqlSession.close();
}
}
按结果集映射
实体类中必须有与sql查询结果集对应类型、数量的构造方法。如这里查询出sid,sname,tname三个结果字段,那么teacher和student类中也要都有对应的int,string,string构造方法
<?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="com.zc.mapper.TeacherMapper">
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.name tname from teacher t,student s where t.id=s.tid and t.id = #{id}
</select>
<resultMap id="TeacherStudent" type="com.zc.entity.Teacher">
<result property="name" column="tname"></result>
<collection property="students" ofType="com.zc.entity.Student">
<result property="id" column="sid"></result>
<result property="name" column="sname"></result>
</collection>
</resultMap>
</mapper>
七、动态sql
-
if语句–这样写有个弊端就是当name为null时,语句后面会变为where and position=#{position}
<?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="com.zc.mapper.HeroMapper"> <select id="selectHerosIf" resultType="com.zc.entity.Hero"> select * from hero where <if test="name!=null"> name=#{name} </if> <if test="position!=null"> and position=#{position} </if> </select> </mapper>
-
where
<?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="com.zc.mapper.HeroMapper"> <select id="selectHerosIf" resultType="com.zc.entity.Hero"> select * from hero <where> <if test="name!=null"> name=#{name} </if> <if test="position!=null"> and position=#{position} </if> </where> </select> </mapper>
-
set
<?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="com.zc.mapper.HeroMapper"> <update id="updateHero"> update hero <set> <if test="name!=null"> name=#{name} </if> <if test="position!=null"> position=#{position} </if> </set> <where> age=#{age} </where> </update> </mapper>
-
choose
<?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="com.zc.mapper.HeroMapper"> <select id="seHerosChoose" resultType="com.zc.entity.Hero"> select * from hero <where> <choose> <when test="name!=null"> name=#{name} </when> <when test="position!=null"> and position=#{position} </when> <when test="age!=null"> and age=#{age} </when> </choose> </where> </select> </mapper>
-
Foreach
八、缓存
1、简介
- 定义:存在内存中的临时数据
- 为什么使用缓存:减少与数据库交互数据,提高系统效率
- 什么样数据使用缓存:经常查询且不经常改变的数据
2、mybatis缓存
默认两级缓存:一级缓存、二级缓存
- 默认情况下只有一级缓存开启–也叫本地缓存,与数据库同一次会话期间查询到的数据会放在本地缓存。是sqlsession级别的缓存,一直开启,我们关闭不了。
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存–也叫全局缓存
- mybatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存
3、使用二级缓存步骤–只有当会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中
- 开启全局缓存
<!--mybatis-config.xml中配置-->
<setting name="cacheEnabled" value="true"></setting>
- 在每一个mapper.xml中配置使用二级缓存
<!--这个配置创建了一个FIFO缓存,每隔60秒刷新,最多可以存储结果对象或列表的512个应用,返回的对象被认为是只读的。-->
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true">