文章目录
1. MyBatis 简介
-
有 MyBatis 就不需要 dao 层的实现类,当 service 直接来调用 dao 接口中的方法,他就能自动去实现 sql 语句
-
定制化 sql ,就是自己随意写 sql 语句
-
存储过程:使用 sql 语句逻辑代码来实现的一个查询过程。即用 sql 写一段代码
-
<!DOCTYPE configuration。
<!DOCTYPE 后面的单词就是 xml 文件的根标签
HelloWord
package com.xp.entity;
public class User {
String uname;
String upass;
@Override
public String toString() {
return "User{" +
"uname='" + uname + '\'' +
", upass='" + upass + '\'' +
'}';
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpass() {
return upass;
}
public void setUpass(String upass) {
this.upass = upass;
}
}
UserMapper 类:
package com.xp.mapper;
import com.xp.entity.User;
public interface UserMapper {
User getUserByUid(String uname);
}
核心配置文件 mybatis-config.xml:
<?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>
<settings>
<!--建议显示的指定我们需要配置的值,防止版本更新带来的问题-->
<!--开启驼峰命名规则-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<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/mysqltest?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<!--<mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
<!--也可以使用package <package name=""></package>-->
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>
映射配置文件 UserMapper.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.UserMapper">
<!--id 是接口中的方法名(因为绑定:接口全限定名和映射文件绑定)
<select>:定义查询语句
id:设置 SQL 语句的唯一标识
resultType:结果类型,即实体类的全限定名
-->
<select id="getUserByUid" resultType="com.xp.entity.User" parameterType="java.lang.String">
select * from user where uname= #{uname}
</select>
</mapper>
Test 类:
import com.xp.entity.User;
import com.xp.mapper.UserMapper;
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.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyTest {
/**
* 1、接口式编程
* 原生: Dao ====> DaoImpl
* mybatis: Mapper ====> xxMapper.xml
*
* 2、SqlSession代表和数据库的一次会话;用完必须关闭;
* 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。
* 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。
* (将接口和xml进行绑定)
* EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class);
* 5、两个重要的配置文件:
* mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
* sql映射文件:保存了每一个sql语句的映射信息:
* 将sql抽取出来。
*/
@Test
public void test01() throws IOException {
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory=
new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession=sqlSessionFactory.openSession();
// getMapper():会通过动态代理动态生成 UserMapper 的代理实现类
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
User user=mapper.getUserByUid("zs");
System.out.println(user);
}
}
- 类里面属性的名字和数据库中的字段名或者字段名的别名要一致
Environment
- resource :在类路径下访问资源文件
- url:在网络路径或磁盘路径下访问资源文件
<?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>
<settings>
<!--建议显示的指定我们需要配置的值,防止版本更新带来的问题-->
<!--开启驼峰命名规则-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--
<environments>:设置数据库的环境
default:设置默认的数据库环境
-->
<environments default="development">
<!-- environment:设置某个具体的数据库环境 -->
<environment id="development">
<!-- type="MANAGED" 被管理的,就是谁能管理事务就让谁管理,比如 Spring 就能管理-->
<transactionManager type="JDBC"/>
<!--type=POOLED|UNPOOLED|JNDI-->
<!--
POOLED:使用 mybatis 默认的自带的连接池(使用连接池会将当前连接进行缓存)
UNPOOLED:不使用数据库连接池,也就是每次连接都会创建一个新的连接
JNDI:调用上下文的数据源(下面的 dataSource 就是一个数据源)
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mysqltest?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<!--<mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
<!--也可以使用package <package name=""></package>-->
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>
- 核心配置文件的标签是有先后顺序的
typeAliases
<typeAliases>
<!-- type:java类型,一般填类的全限定名,若只设置 type,默认的别名就是类名,且不区分大小写。若要自己设置别名,加一个 alias="要设置的名字" -->
<!--<typeAlias type="com.xp.entity.User" alias="u"></typeAlias>-->
<!-- 还有一种用法:-->
<package name="com.xp.entity"/> <!--这个就是为这个包名下的所有类创建别名,别名为类名-->
</typeAliases>
mapper 和 xml 的增删改查
JDBC 的事务必须手动提交,两种方式,sqlSession.commit() 或者 openSession(true)
实体类emp:
public class Emp {
Integer eid;
String ename;
String sex;
public Emp(Integer eid, String ename, String sex) {
this.eid = eid;
this.ename = ename;
this.sex = sex;
}
public Emp(String ename, String sex) {
this.ename = ename;
this.sex = sex;
}
public Integer getEid() {
return eid;
}
public void setEid(Integer eid) {
this.eid = eid;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Emp{" +
"eid=" + eid +
", ename='" + ename + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
EmpMapper类:
package com.xp.mapper;
import com.xp.entity.Emp;
import java.util.List;
public interface EmpMapper {
//增
Integer addEmp(Emp emp);
//删
Integer deleteEmp(Integer eid);
//改
Integer updateEmp(Emp emp);
//查by id
Emp getEmpById(Integer eid);
//查 all
List<Emp>getAllEmp();
}
EmpMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<!--id 是接口中的方法名(因为绑定:接口全限定名和映射文件绑定)
<select>:定义查询语句
id:设置 SQL 语句的唯一标识
resultType:结果类型,即实体类的全限定名
-->
<!-- Integer addEmp(Emp emp); -->
<insert id="addEmp" parameterType="com.xp.entity.Emp">
insert into Emp(ename,sex) values(#{ename},#{sex})
</insert>
<!-- Integer deleteEmp(Integer eid);-->
<delete id="deleteEmp" parameterType="java.lang.Integer">
delete from Emp where eid=#{eid}
</delete>
<!-- Integer updateEmp(Emp emp);-->
<update id="updateEmp" parameterType="com.xp.entity.Emp">
update Emp set ename=#{ename},sex=#{sex} where eid=#{eid}
</update>
<!-- Emp getEmpById(Integer eid);-->
<select id="getEmpById" resultType="com.xp.entity.Emp">
select * from emp where eid=#{eid}
</select>
<!-- List<Emp>getAllEmp();-->
<!--这里的返回值类型填 Emp,因为他会自动把 Emp 放到 List 集合中-->
<select id="getAllEmp" resultType="com.xp.entity.Emp">
select * from emp
</select>
</mapper>
Test 类:
public class MyTest
{
@Test
public void test01() throws IOException {
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory=
new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession=sqlSessionFactory.openSession(true); //设置为 true ,事务自动提交
EmpMapper mapper=sqlSession.getMapper(EmpMapper.class);
//测试增加员工
//System.out.println(mapper.addEmp(new Emp("李四","男")));
//测试查询员工 byid
//System.out.println(mapper.getEmpById(3));
//查询所有员工
/*for (Emp emp : mapper.getAllEmp()) {
System.out.println(emp);
}*/
//更新员工信息
//System.out.println(mapper.updateEmp(new Emp(2,"ls","女")));
//删除员工信息
//System.out.println(mapper.deleteEmp(1));
}
}
通过 package 管理映射文件的引入
可以在 resources 下面创建一个包,通过 package 的方式,可以把那个包下的所有 xml 文件引入进来,如:
<mappers>
<!-- 这种写法要求 mapper 接口和 mapper 映射文件必须在同一个包下-->
<package name="com.xp.mapper"/>
</mappers>
MyBatis 获取参数值的两种方式 ${} 和 #{}
#{}:PreparedStatement(通过通配符赋值,可以防止 sql 注入)
${}:Statement(字符串拼接,需要注意单引号问题)
使用建议:建议使用 #{},在特殊情况下,需要使用 ${} ,比如模糊查询和批量操作
MyBatis 实现添加时获取自动生成的主键
在 JDBC 里面:
PreparedStatement ps=con.prepareStatement("",1)//这个1就是允许获取自动生成的主键的意思
...
ResultSet rs=ps.getGenerateKeys() //获取自动生成的主键
rs.next();
int id=rs.getInt(1) //获取自动生成的主键
在 MyBatis 里面:
<!--
useGeneratedKeys:可以使用自动生成的主键
keyProperty:将获取到的自动生成的主键赋值给Emp(传递过来的参数)哪个属性
-->
<insert id="addEmp" parameterType="com.xp.entity.Emp" useGeneratedKeys="true" keyProperty="eid">
insert into Emp(ename,sex) values(#{ename},#{sex})
</insert>
MyBatis 获取不同参数值的方式1
不同的参数类型,${} 和 #{} 的不同取值方式:
1、当传输参数为单个 String 或基本数据类型和其包装类
#{}:可以以任意的名字获取参数值
${}:只能以 ${value} 或 ${_parameter} 获取
2、当传输参数为 JavaBean 时
#{} 和 ${} 都可以通过属性名直接获取属性值,但是要注意 ${} 的单引号问题
3、当传输多个参数时
两种方式:
(1)键为arg0,arg1…argN
(2)键为 param1,param2…paramN
#{}:#{arg0},#{param1}
:
{}:
:{arg0},${param1}
Emp getEmpById(Integer eid,String ename);
<select id="getEmpById" resultType="com.xp.entity.Emp">
select * from emp where eid=#{arg0} and ename=#{arg1}
</select>
4、当传输参数为 map 时
#{} 和 ${} 都可以通过属性名直接获取属性值,但是要注意 ${} 的单引号问题
5、命名参数
可以通过注解 @Param 为 map 指定键的名字
#{} 和 ${} 都可以通过属性名直接获取属性值,但是要注意 ${} 的单引号问题
6、当传输参数为 List 或 Array,MyBatis 会将 List 或 Array 放在 map 中
List 以 list 为键,Array 以 array 为键
多对一自定义映射
Emp 类(一定要有空的构造器):
package com.xp.entity;
public class Emp {
Integer eid;
String ename;
String sex;
Dept dept; // 一个员工对应一个部门
public Emp() {
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public Emp(Integer eid, String ename, String sex, Dept dept) {
this.eid = eid;
this.ename = ename;
this.sex = sex;
this.dept = dept;
}
public Emp(String ename, String sex) {
this.ename = ename;
this.sex = sex;
}
public Integer getEid() {
return eid;
}
public void setEid(Integer eid) {
this.eid = eid;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Emp{" +
"eid=" + eid +
", ename='" + ename + '\'' +
", sex='" + sex + '\'' +
", dept=" + dept +
'}';
}
}
EmpMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<resultMap id="empdept" type="com.xp.entity.Emp">
<!--id 表示主键的 column 和 property 的对应关系-->
<id column="eid" property="eid"></id>
<!-- column 对应数据库字段,property 对应类的属性名-->
<result column="ename" property="ename"></result>
<result column="sex" property="sex"></result>
<result column="did" property="dept.did"></result>
<result column="dname" property="dept.dname"></result>
</resultMap>
<!-- List<Emp>getAllEmp();-->
<!--这里的返回值类型填 Emp,因为他会自动把 Emp 放到 List 集合中-->
<!--resultMap:实现将查询结果映射为复杂类型的pojo(就像这里的Emp类,他还包含一个类Dept,所以可以将查询结果做个映射)-->
<select id="getAllEmp" resultMap="empdept">
select e.eid,e.ename,e.sex,d.did,d.dname from emp e left join dept d on e.did=d.did
</select>
</mapper>
使用 association 完成多对一映射
其他类和上面一样
EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<resultMap id="empdept" type="com.xp.entity.Emp">
<!--id 表示主键的 column 和 property 的对应关系-->
<id column="eid" property="eid"></id>
<!-- column 对应数据库字段,property 对应类的属性名-->
<result column="ename" property="ename"></result>
<result column="sex" property="sex"></result>
<!--association:写嵌套的那个类-->
<association property="dept" javaType="com.xp.entity.Dept">
<id column="did" property="did"></id>
<result column="dname" property="dname"></result>
</association>
</resultMap>
<!-- List<Emp>getAllEmp();-->
<!--这里的返回值类型填 Emp,因为他会自动把 Emp 放到 List 集合中-->
<select id="getAllEmp" resultMap="empdept">
select e.eid,e.ename,e.sex,d.did,d.dname from emp e left join dept d on e.did=d.did
</select>
</mapper>
多对一分步查询
EmpMapper.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<resultMap id="empdept" type="com.xp.entity.Emp">
<!--id 表示主键的 column 和 property 的对应关系-->
<id column="eid" property="eid"></id>
<!-- column 对应数据库字段,property 对应类的属性名-->
<result column="ename" property="ename"></result>
<result column="sex" property="sex"></result>
<!--
select :去找到一个 sql ,select 的值就是这个sql的id ,查询结果为 dept 的来给 dept 赋值
id 就是一个方法名,方法名在接口里面,所以完整的表示应该为:接口全限定名.方法名
column:就是把选中的那个字段作为分步查询的条件
-->
<association property="dept" javaType="com.xp.entity.Dept" select="com.xp.mapper.DeptMapper.getDeptById" column="did">
</association>
</resultMap>
<!-- List<Emp>getAllEmp();-->
<!--这里的返回值类型填 Emp,因为他会自动把 Emp 放到 List 集合中-->
<select id="getAllEmp" resultMap="empdept">
select e.eid,e.ename,e.sex,e.did from emp
</select>
</mapper>
DeptMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.DeptMapper">
<!--这个id标识的是一个方法名,所以只需要接口全限定名.方法名就可以在工程里面唯一标识这个 select-->
<select id="getDeptById" resultType="com.xp.entity.Dept">
select did,dname from dept where did=#{did}
</select>
</mapper>
分步查询的延迟加载
对于上面三种多对一的写法中,延迟加载只针对分步查询,延迟加载就是要用的时候才加载,延迟加载又叫懒加载。在核心配置文件(mapper-config.xml) 中的 setting 标签进行配置
<settings>
<!-- 开启全局性设置懒加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 开启按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
一对多自定义映射
案例描述:根据 Dept_id 查出来一个部门的所有员工信息
public interface DeptMapper {
//public Dept getDeptById(Integer id);
public List<Dept> getDeptEmpsById(Integer id);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.DeptMapper">
<resultMap id="deptemp" type="Dept">
<id column="did" property="did"></id>
<result column="dname" property="dname"></result>
<!-- association是用于一对一和多对一,而collection是用于一对多的关系 -->
<!--JavaType和ofType都是用来指定对象类型的,但是JavaType是用来指定pojo中属性的类型,而ofType指定的是映射到list集合属性中pojo的类型-->
<collection property="emps" ofType="Emp">
<id column="eid" property="eid"></id>
<result column="ename" property="ename"></result>
<result column="sex" property="sex"></result>
</collection>
</resultMap>
<!-- public List<Dept> getDeptEmpsById(Integer id) -->
<select id="getDeptEmpsById" resultMap="deptemp">
select d.did,d.dname,e.eid,e.ename,e.sex from dept d left join emp e on d.did=e.did where d.did=#{did}
</select>
</mapper>
一对多分步查询
DeptMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.DeptMapper">
<resultMap id="deptemp" type="Dept">
<id column="did" property="did"></id>
<result column="dname" property="dname"></result>
<collection property="emps" ofType="Emp" select="com.xp.mapper.EmpMapper.getEmpById" column="did"></collection>
</resultMap>
<!-- public List<Dept> getDeptEmpsById(Integer id) -->
<select id="getDeptEmpsById" resultMap="deptemp">
select d.did,d.dname from dept d where did=#{did}
</select>
</mapper>
EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<!--Emp getEmpById(Integer did)-->
<select id="getEmpById" resultType="Emp">
select * from emp where did=#{did}
</select>
</mapper>
这里注意一个问题就是,如果 column 有多个值需要传的话,就可以用 map 的形式,即 {did=did},前面那个 did 就是你后面EmpMapper.xml sql里面的#{}中的那个did,后面的 did 就是DeptMapper.xml <id column="did" property="did"></id>
中的property查出来的值
还有一个问题就是你不想指定全局延迟加载的时候,可以用 fetchType ,指定某个 sql 的延迟加载
动态 SQL
<if test=""></if>: 通过 test 表达式,拼接 SQL
<where></where>:Where可以在处理条件时,自动的去掉以and、or开始的字符串。如果把 and 写在语句的尾,该报错还是会报错。不过可以用 trim 解决 and 在语句末尾的情况
<trim>:事实上trim标签有点类似于replace效果。
trim 属性
prefix:前缀覆盖并增加其内容
suffix:后缀覆盖并增加其内容
prefixOverrides:前缀判断的条件
suffixOverrides:后缀判断的条件
<set>:主要是用于解决修改操作中能够 SQL 语句中可能多出逗号的问题。一般用于update语句,生成set column=?
<choose>:主要是用于分支判断,类似于 Java 中的 switch case ,只会满足所有分支中的一个
动态 SQL 之 if
mybatis 映射文件中,if标签判断字符串相等,两种方式:因为mybatis映射文件,是使用的ognl表达式,所以在判断字符串sex变量是否是字符串Y的时候使用
<test="sex=='Y'.toString()">或者<test = 'sex== "Y"'>
因为mybatis会把’Y’解析为字符,java是强类型语言,所以不能这样写。
EmpMapper类:
public interface EmpMapper {
public List<Emp> getAllEmpByCondition(Emp emp);
}
EmpMapper.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<!-- public List<Emp> getAllEmpByCondition(Emp emp) -->
<select id="getAllEmpByCondition" resultType="com.xp.entity.Emp" parameterType="com.xp.entity.Emp">
select eid,ename,sex from emp where
1=1
<if test="eid!=null">and eid=#{eid}</if>
<if test="ename!='' and ename!=null">and ename=#{ename}</if>
<if test="sex=='男'.toString() or sex=='女'.toString()"> and sex=#{sex}</if>
</select>
</mapper>
动态 SQL 之 where
和上面等价的写法:
EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<!-- public List<Emp> getAllEmpByCondition(Emp emp) -->
<select id="getAllEmpByCondition" resultType="com.xp.entity.Emp" parameterType="com.xp.entity.Emp">
select eid,ename,sex from emp
<where>
<if test="eid!=null">and eid=#{eid}</if>
<if test="ename!='' and ename!=null">and ename=#{ename}</if>
<if test="sex=='男'.toString() or sex=='女'.toString()"> and sex=#{sex}</if>
</where>
</select>
</mapper>
动态 SQL 之 trim
等价上面的 EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<!-- public List<Emp> getAllEmpByCondition(Emp emp) -->
<select id="getAllEmpByCondition" resultType="com.xp.entity.Emp" parameterType="com.xp.entity.Emp">
select eid,ename,sex from emp
<!--
<trim>:截取并拼接
prefix:在操作的 SQL 前加入某些内容
prefixOverrides:把操作的 SQL 语句前的某些内容去掉
suffix:在操作的 SQL 后加入某些内容
suffixOverrides:把操作的 SQL 语句后的某些内容去掉
-->
<trim prefix="where" suffixOverrides="and|or">
<if test="eid!=null">eid=#{eid} and</if>
<if test="ename!='' and ename!=null">ename=#{ename} and</if>
<if test="sex=='男'.toString() or sex=='女'.toString()">sex=#{sex}</if>
</trim>
</select>
</mapper>
动态 SQL 之 choose
<choose>
选择一个条件进行判断
EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<!-- public List<Emp> getAllEmpByCondition(Emp emp) -->
<select id="getAllEmpByCondition" resultType="com.xp.entity.Emp" parameterType="com.xp.entity.Emp">
select eid,ename,sex from emp
<!--
<trim>:截取并拼接
prefix:在操作的 SQL 前加入某些内容
prefixOverrides:把操作的 SQL 语句前的某些内容去掉
suffix:在操作的 SQL 后加入某些内容
suffixOverrides:把操作的 SQL 语句后的某些内容去掉
-->
<where>
<choose>
<when test="eid!=null"> eid=#{eid} </when>
<when test="ename!='' and ename!=null">ename=#{ename}</when>
<when test="sex=='男'.toString() or sex=='女'.toString()">sex=#{sex}</when>
</choose>
</where>
</select>
</mapper>
批量删除
三种方法
第一种:用 in
EmpMapper.Java 类:
package com.xp.mapper;
import com.xp.entity.Emp;
import java.util.List;
public interface EmpMapper {
// 通过 eid 所组成的字符串实现批量删除
public void deleteMoreEmp(String eids);
}
EmpMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<!--public void deleteMoreEmp(String eids)-->
<delete id="deleteMoreEmp" parameterType="java.lang.String">
delete from emp where eid in (${value})
</delete>
</mapper>
测试类:
public class MyTest
{
@Test
public void test01() throws IOException {
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory=
new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession=sqlSessionFactory.openSession(true); //设置为 true ,事务自动提交
EmpMapper mapper=sqlSession.getMapper(EmpMapper.class);
mapper.deleteMoreEmp("1,2,3");
}
}
第二种方法:
使用 foreach 实现批量删除
EmpMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xp.mapper.EmpMapper">
<!-- public void deleteMoreByList(List<Integer>emps) -->
<delete id="deleteMoreByList">
delete from emp where eid in(
<!--这里的 collection 不写前面 List 的名字emps ,而写 list 是因为:
当传输参数为 List 或 Array,MyBatis 会将 List 或 Array 放在 map 中
List 以 list 为键,Array 以 array 为键
-->
<!--
<foreach>:对一个数组或集合进行遍历
collection: 指定要遍历的集合或数组
item:设置别名
close:设置循环体的结束内容
open:设置循环体的开始内容
separator:设置每一次循环的分隔符
index:若遍历的是 List,index 代表下标,若遍历的是 map,index 代表键
-->
<foreach collection="list" separator="," item="emp">
#{emp}
</foreach>
)
</delete>
</mapper>
EmpMapper.Java 类:
public interface EmpMapper {
// 通过 list 集合实现批量删除
public void deleteMoreByList(List<Integer>emps);
}
动态 SQL 之 sql
<!-- <sql>: 设置一段 SQL 片段,即公共 SQL,可以被当前映射文件中所有SQL语句所访问-->
<sql id="selectemp">select * from emp</sql>
然后通过 :
<include refid="selectemp"></include>
进行使用
MyBatis 的缓存
MySQL 一般是把数据存在磁盘中,缓存就是把数据存放在内存中
- 二级缓存在操作实体类的时候,这个实体类必须实现了 Serializable 接口
- 缓存回收策略:就是内存的大小是有限的,当内存放不下的时候,就应该清理缓存,这个就是指清理缓存的策略
缓存机制简介
(1)MyBatis 是一个包含非常强大的查询缓存特性,它可以非常方便地配置和定制,缓存可以极大的提升查询效率
(2)MyBatis 系统中默认定义了两级缓存
- 一级缓存
- 二级缓存
(3)默认情况下,只有一级缓存(SqlSession 级别的缓存,也称为本地缓存)开启
(4)二级缓存需要手动开启和配置,他是基于 namespace 级别的缓存
(5)为了提高扩展性,MyBatis 定义了缓存接口 Cache ,我们可以通过实现 Cache 接口来自定义二级缓存
一级缓存的使用
(1)一级缓存,即本地缓存,作用域默认 sqlSession,当 Session flush 或 close 后,该 Session 中所有 Cache 将被清空
(2)本地缓存不能关闭,但可以调用 clearCache() 来清空本地缓存,或者改变缓存的作用域
(3)在 MyBatis3.1 之后,可以配置本地缓存的作用域,在 MyBatis.xml 中配置
二级缓存的使用
(1)二级缓存,全局作用缓存
(2)二级缓存默认不开启,需要手动配置
(3)MyBatis 提供二级缓存的接口以及实现,缓存实现要求 pojo 实现 Serializable 接口
(4)二级缓存在 SQLSession 关闭或提交之后才会生效
(5)二级缓存的使用步骤:
①全局配置文件中开启二级缓存 <setting name="cacheEnable" value="true">
②需要使用二级缓存的映射文件处使用 cache 配置缓存 <cache />
③注意:POJO 需要实现 Serializable 接口
(6)二级缓存相关的属性
① eviction="FIFO"
:缓存回收策略
LRU:最近最少使用的,移除最长时间不被使用的对象
FIFO:先进先出,按对象进入缓存的顺序来移除它们
SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
WEAK:弱引用,移除基于垃圾回收器状态和弱引用规则的对象