目录
动态SQL
if
在select标签中可以使用if标签来判断,比如在多条件查询的应用场景中我们需要根据用户的输入而动态的调整sql语句,若用户没有输入,name这个条件就不能在sql语句中存在。我们可以使用if标签来判断是否为null或者空值,来动态的拼接sql语句。
<select id="getEmpListByMoreTJ" resultType="emp">
select * from emp WHERE
<if test="eid != null">
eid = #{eid}
</if>
<if test="ename != null and ename != ''">
AND ename = #{ename}
</if>
<if test="age != null">
and age = #{age}
</if>
<if test="sex == '1' or sex == '2'">
and sex = #{sex}
</if>
</select>
where
上面的sql语句中如果第一的条件不存在,那么sql语句就会变成下面那样,很明显多了一个and,sql不能正确执行。
select * from emp WHERE AND ename = ? and age = ?
这里我们就需要引入where标签来解决这个问题。使用where标签以后就不用在sql语句中写where了。where 标签的作用是添加where并且去掉多余的and
<select id="getEmpListByMoreTJ" resultType="emp">
select * from emp
<where>
<if test="eid != null">
eid = #{eid}
</if>
<if test="ename != null and ename != ''">
AND ename = #{ename}
</if>
<if test="age != null">
and age = #{age}
</if>
<if test="sex == '1' or sex == '2'">
and sex = #{sex}
</if>
</where>
</select>
trim
还可以使用trim标签来解决上面那个问题。trim标签有四个属性,分别是:
- prefix:在操作的SQL语句前加入某些内容
- suffix:在操作的SQL语句后加入某些内容
- prefixOverrides:把操作的SQL语句前的某些内容去掉
- suffixOverrides:把操作的SQL语句后的某些内容去掉
<select id="getEmpListByMoreTJ" resultType="emp">
select * from emp
<trim prefix="where" suffixOverrides="and">
<if test="eid != null">
eid = #{eid} and
</if>
<if test="ename != null and ename != ''">
ename = #{ename} AND
</if>
<if test="age != null">
age = #{age} and
</if>
<if test="sex == '1' or sex == '2'">
sex = #{sex}
</if>
</trim>
</select>
choose
可以使用choose标签来实现根据某一个条件查询,这里要注意的是只要满足一个条件下面的条件都不会执行。
<!--//根据eid ename age sex其中一个查询员工信息-->
<!--List<Emp> getEmpListByChosse(Emp emp);-->
<select id="getEmpListByChosse" resultType="emp">
select * from emp
<where>
<choose>
<when test="eid != null">
eid = #{eid}
</when>
<when test="ename != null and ename != ''">
ename = #{ename}
</when>
<when test="age != null">
age = #{age}
</when>
<otherwise>
sex = #{sex}
</otherwise>
</choose>
</where>
</select>
foreach
实现批量删除1 — 使用${}的方式
String eids = "27,28";
mapper.deleteMoreEmp(eids);
<!--//通过eid所组成的字符串-->
<!--void deleteMoreEmp(String eid);-->
<delete id="deleteMoreEmp">
DELETE from emp where eid in (${value})
</delete>
实现批量删除2 — 使用foreach的方式1
使用的sql语句是delete from emp where eid in(…)…
// 测试foreach删除
List<Integer> list = new ArrayList<>();
list.add(15);
list.add(16);
mapper.deleteMoreByList(list);
<!--// 通过List集合实现批量删除-->
<!--void deleteMoreByList(List<Integer> eid);-->
<delete id="deleteMoreByList">
delete from emp where eid in
<foreach collection="list" item="eid" separator="," open="(" close=")" >
#{eid}
</foreach>
</delete>
实现批量删除3 — 使用foreach的方式2
使用的sql语句是delete from emp where eid = ? or eid = ? …
<delete id="deleteMoreByList">
delete from emp where
<foreach collection="list" item="eid" separator="or">
eid = #{eid}
</foreach>
</delete>
批量增删改查
要注意批量修改使用多条sql语句的时候必须在连接地址(url)后添加参数?allowMultiQueries=true
delete:
delete from emp where eid in ();
delete from emp where eid = 1 or eid = 2 or eid = 3
select:
select * from emp where eid in ();
select * from emp where eid = 1 or eid = 2 or eid = 3
update:
把每条数据修改为相同内容
update emp set ... where eid in ();
update emp set ... where eid = 1 or eid = 2 or eid = 3
把每条数据修改为对应内容,注意:必须在连接地址(url)后添加参数?allowMultiQueries=true
update emp set ... where eid = 1;
update emp set ... where eid = 2;
update emp set ... where eid = 3
insert
insert into emp values(),(),()
批量添加:
<!-- void insertMoreByArray(Emp[] emps); -->
<insert id="insertMoreByArray">
insert into emp values
<foreach collection="emps" item="emp" separator=",">
(null,#{emp.ename},#{emp.age},#{emp.sex},1)
</foreach>
</insert>
批量修改:
<!-- void updateMoreByArray(@Param("emps")Emp[] emps); -->
<update id="updateMoreByArray">
<foreach collection="emps" item="emp">
update emp set ename = #{emp.ename}, age = #{emp.age}, sex = #{emp.sex} where eid = #{emp.eid};
</foreach>
</update>
sql
可以通过sql标签定义一段公共的sql语句,然后通过include标签引入
<!--
<sql id=""></sql>:设置一段SQL片段,即公共SQL,可以被当前映射文件中所有的SQL语句所访问
<include refid="empColumns"></include>:访问某个SQL片段
-->
<sql id="empColumns">select eid,ename,age,sex,did from emp </sql>
<!-- Emp getEmpByEid(String eid); -->
<select id="getEmpByEid" resultType="Emp">
<include refid="empColumns"></include> where eid = #{eid}
</select>
mybatis的缓存机制
Mybatis提供了两级缓存,可以提高查询的效率。
一级缓存
一级缓存是默认开启的,作用域为sqlSession,Session flush 或 close 后, 该 Session 中的所有 Cache 将被清空。一级缓存不能被关闭,可以使用 clearCache() 方法来清空缓存。
一级缓存失效的条件:
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清空了缓存
@Test
public void testSQL() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp empById = mapper.getEmpById("1");
System.out.println(empById);
//清空缓存
// sqlSession.clearCache();
//之间执行了一次增删改操作
mapper.deleteMoreEmp("37");
System.out.println("----------------------");
Emp empById1 = mapper.getEmpById("1");
System.out.println(empById1);
}
二级缓存
二级的缓存是针对于映射文件的,是全局的,默认不开启,需要手动配置开启。
使用步骤:
- 在mybatis的核心配置文件中使用setting标签开启二级缓存
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
- 在想要开启的映射文件中配置缓存
<cache />
- 相应的POJO要实现Serializable接口
public class Emp implements Serializable
注意:二级缓存在sqlsession关闭或者提交之后才会生效。
@Test
public void testTwoSQL() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp empById = mapper.getEmpById("1");
System.out.println(empById);
sqlSession.commit();
System.out.println("-------------------------");
EmpMapper mapper1 = sqlSession.getMapper(EmpMapper.class);
Emp empById1 = mapper1.getEmpById("1");
System.out.println(empById1);
}
1:select标签的useCache属性:
配置这个select是否使用二级缓存。一级缓存一直是使用的
2:sql标签的flushCache属性:
增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。
查询默认 flushCache=false。
3:)sqlSession.clearCache():只是用来清除一级缓存
第三方缓存
使用步骤:
1.导入jar包:
ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar
slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar
2.导入配置文件,ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="D:\atguigu\ehcache" />
<defaultCache
maxElementsInMemory="1"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
3.配置映射文件中的cache标签
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
逆向工程
可以根据数据库的数据表生成相应的javaBean和对应的映射文件。
使用步骤
导入jar包
mybatis-generator-core-1.3.2.jar
编辑配置文件
这里把配置文件命名为mbg.xml,将配置文件修改为自己项目对应的包名即可。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3Simple">
<!-- 设置连接数据库的信息 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm"
userId="root"
password="root">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- javabean的生成策略 -->
<javaModelGenerator targetPackage="com.glq.bean" targetProject=".\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- 映射文件的生成策略 -->
<sqlMapGenerator targetPackage="com.glq.mapper" targetProject=".\conf">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- mapper接口的生成策略 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.glq.mapper" targetProject=".\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 设置要将数据库中的哪张表逆向生成哪一个javabean -->
<table tableName="emp" domainObjectName="Emp"></table>
<table tableName="dept" domainObjectName="Dept"></table>
</context>
</generatorConfiguration>
运行生成器代码
运行完毕以后就会发现相对应的javabean和xml映射文件就配置好了
@Test
public void testMBG() throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
targetRuntime=“MyBatis3Simple”
此时生成的方法比较少,只包含增删改、根据主键查询、查询全部这几个方法。
@Test
public void test1() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> emps = mapper.selectAll();
for (Emp emp:emps){
System.out.println(emp);
}
}
targetRuntime=“MyBatis3”
此时生成的方法比较多,不仅生成了对应的bena,还生成了相应的***Example类,这个类主要用来查询的时候添加条件的。
@Test
public void test1() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
EmpExample empExample = new EmpExample();
EmpExample.Criteria criteria = empExample.createCriteria();
//查询姓名里面含有‘林’,并且年龄为22的员工,或者性别为男的
criteria.andEnameLike("%林%");
criteria.andAgeEqualTo(22);
EmpExample.Criteria criteria1 = empExample.createCriteria();
criteria1.andSexEqualTo("男");
empExample.or(criteria1);
List<Emp> emps = mapper.selectByExample(empExample);
System.out.println(emps);
}
PageHelper分页插件
使用步骤
导入jar包
pagehelper-x.x.x.jar 和 jsqlparser-0.9.5.jar
在核心配置文件中进行配置
注意这个标签写在plugins的上方
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
在java语句中使用
@Test
public void test() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
PageHelper.startPage(6,2);
List<Emp> list = mapper.getAllEmp();
for(Emp emp:list){
System.out.println(emp);
}
PageInfo<Emp> pageInfo = new PageInfo<>(list,5);
System.out.println(Arrays.toString(pageInfo.getNavigatepageNums()) );
}
page对象的使用
@Test
public void testPageHelper() throws Exception{
SqlSessionFactory ssf = getSqlSessionFactory();
SqlSession session = ssf.openSession();
try {
EmployeeMapper mapper =
session.getMapper(EmployeeMapper.class);
//设置分页信息
Page<Object> page = PageHelper.startPage(9, 1);
List<Employee> emps = mapper.getAllEmps();
for (Employee employee : emps) {
System.out.println(employee);
}
System.out.println("=============获取分页相关的信息=================");
System.out.println("当前页: " + page.getPageNum());
System.out.println("总页码: " + page.getPages());
System.out.println("总条数: " + page.getTotal());
System.out.println("每页显示的条数: " + page.getPageSize());
} finally {
session.close();
}
}
pageInfo对象的使用
public void testPageHelper1() throws Exception{
SqlSessionFactory ssf = getSqlSessionFactory();
SqlSession session = ssf.openSession();
try {
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
//设置分页信息
Page<Object> page = PageHelper.startPage(9, 1);
List<Employee> emps = mapper.getAllEmps();
//
PageInfo<Employee> info = new PageInfo<>(emps,5);
for (Employee employee : emps) {
System.out.println(employee);
}
System.out.println("=============获取详细分页相关的信息=================");
System.out.println("当前页: " + info.getPageNum());
System.out.println("总页码: " + info.getPages());
System.out.println("总条数: " + info.getTotal());
System.out.println("每页显示的条数: " + info.getPageSize());
System.out.println("是否是第一页: " + info.isIsFirstPage());
System.out.println("是否是最后一页: " + info.isIsLastPage());
System.out.println("是否有上一页: " + info.isHasPreviousPage());
System.out.println("是否有下一页: " + info.isHasNextPage());
System.out.println("============分页逻辑===============");
int [] nums = info.getNavigatepageNums();
for (int i : nums) {
System.out.print(i +" " );
}
} finally {
session.close();
}
}
实现分页操作
要实现下面这种效果:
首页 上一页 1 2 3 4 5 下一页 末页
public void getPageInfo(PageInfo<Emp> pageInfo, HttpServletRequest req){
String path = req.getContextPath() + "/";
StringBuilder builder = new StringBuilder();
//拼接首页
builder.append("<a href='"+path+"emps/1'>首页</a>");
//拼接上一页
if(pageInfo.isHasPreviousPage()){
builder.append("<a href='"+path+"emps/"+pageInfo.getPrePage()+"'></a>");
}else{
builder.append("上一页");
}
//拼接页码
int[] nums = pageInfo.getNavigatepageNums();
for(int i : nums){
if(i == pageInfo.getPageNum()){
builder.append("<a style='color:red;' href='"+path+"emps/"+i+"'>"+i+"</a>");
}else{
builder.append("<a href='"+path+"emps/"+i+"'>"+i+"</a>");
}
}
//拼接下一页
if(pageInfo.isHasNextPage()){
builder.append("<a href='"+path+"emps/"+pageInfo.getNextPage()+"'></a>");
}else{
builder.append("下一页");
}
//拼接末页
builder.append("<a href='"+path+"emps/"+pageInfo.getPages()+"'>尾页</a>");