Mybatis框架

Mybatis框架

MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。

Mybatis不是一个完全的orm框架,Mybatis需要程序员自己写sql,但是也存在映射(输入参数映射,输出结果映射),学习门槛mybatis比hibernate低;同时灵活性高,特别适用于业务模型易变的项目,使用范围广。

应用场合:在日常的开发项目中,如中小型项目,例如ERP,需求与关系模型相对固定建议使用Hibernate,对于需求不固定的项目,比如:互联网项目,建议使用mybatis,因为需要经常灵活去编写sql语句。

mybatis提供两种配置文件, 核心配置文件 mybatis.xml 与 SQL映射文件mapper.xml。

1. Mybatis文件配置

db.properties配置文件:

driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:XE
username=SCOTT
password=TIGER

mybatis.xml文件配置内容:





<configuration>

    
    <properties resource="db.properties" />

    
    <settings>
        
        <setting name="logImpl" value="LOG4J"/>
    settings>

    <typeAliases>
        <package name="com.pojo"/> 
    typeAliases>

    
    <environments default="ev">
        
        <environment id="ev">
            
            <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/mappers/deptmapper.xml"/>
        <mapper resource="com/mappers/deptmapper2.xml"/>
        <mapper resource="com/mappers/empmapper.xml"/>
        <mapper resource="com/mappers/deptmapper3.xml"/>
    mappers>
configuration>

2. 查询操作

  • selectList(“命名空间.id”) 用户查询多条数据情况,返回一个List集合, 没有查到数据返回空集合,不是null
  • selectOne(“命名空间.id”) 用于查询单条数据,返回一个数据, 如果没有查到返回null
  • selectMap(“命名空间.id”,key的字段名) 用于查询多条记录情况, 返回Map集合, 需要指定那个属性作为key, sql查询结果作为value,指定的字段值作为key, 如果查不到, 返回一个空map集合,不是null

定义Dept类javabean:

private Integer deptno;
private String dname;
private String loc;

deptmapper(sql映射文件):




<mapper namespace="com.mappers.deptmapper">
    
    <select id="queryAll" resultType="Dept">
        select * from dept
    select>
    <select id="querybydeptno" parameterType="int" resultType="dept">
        select * from dept where deptno = #{deptno}
    select>
mapper>

测试代码:

import com.pojo.Dept;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

public class TestDept01 {
     
    public static void main(String[] args) throws IOException {
     
        //1.加载执行核心配置文件
        InputStream is = Resources.getResourceAsStream("mybatis.xml");
        //2.构建SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //3.根据工厂获取回话
        SqlSession session = factory.openSession();
        //4.执行指定的sql
        //selectList("命名空间.id")
        List<Dept> list = session.selectList("com.mappers.deptmapper.queryAll");
        //selectOne("命名空间.id")
        //selectOne("命名空间.id",入参)
        Dept d1 = session.selectOne("com.mappers.deptmapper.querybydeptno",20);
        //selectMap("命名空间.id","作为key的字段名")
        //selectMap("命名空间.id",入参,"作为key的字段名")
        Map<Integer,Dept> map = session.selectMap("com.mappers.deptmapper.queryAll",10,"deptno");
        //5.处理数据
        list.forEach(System.out::println);
        System.out.println(d1);
        System.out.println(map);
        //6.关闭回话
        session.close();
    }
}

3. 入参类型和结果类型

  • 入参类型(parameterType)包括基本数据类型及其包装类 String Date Javabean Map List 数组 …

  • 结果类型(resultType)包括基本数据类型及其包装类 String Date JavaBean List Map List

具体通过代码来进行演示:

deptmapper2(sql映射文件):



<mapper namespace="com.mappers.deptmapper2">
    
    <select id="queryallbydeptno" parameterType="int" resultType="Dept">
        select * from dept where deptno = #{deptno}
    select>
    
    <select id="querydeptbydname" parameterType="string" resultType="Dept">
        select * from dept where dname = #{dname}
    select>
    
    <select id="querybynoname" parameterType="Dept" resultType="Dept">
        select * from dept where deptno = #{deptno} and dname = #{dname}
    select>
    
    <select id="querybydeptnos" resultType="Dept">
        select * from dept where deptno in (
        <foreach collection="array" item="item" separator=",">
            #{item}
        foreach>
        )
    select>
    
    <select id="querybynos" parameterType="list" resultType="Dept">
        select * from dept where deptno in (
        <foreach collection="list" item="item" separator=",">
            #{item}
        foreach>
        )
    select>
    
    <select id="querybynoorname" parameterType="map" resultType="Dept">
        select * from dept where dname = #{dname} or loc = #{loc}
    select>
mapper>

测试代码:

import com.pojo.Dept;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TestDept02 {
     
    public static void main(String[] args) throws IOException {
     
        SqlSession session =  new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml")).openSession();
        //测试入参为基本数据类型|包装类
        Dept d2 = session.selectOne("com.mappers.deptmapper2.queryallbydeptno",10);
        System.out.println(d2);
        //测试入参为String类型
        List<Dept> list = session.selectList("com.mappers.deptmapper2.querydeptbydname","SALES");
        System.out.println(list);
        //测试入参为javabean类型
        Dept d1 = session.selectOne("com.mappers.deptmapper2.querybynoname",new Dept(20,"RESEARCH",null));
        System.out.println(d1);
        //测试入参为数组类型
        int[] arr = {
     20,30,40};
        List<Dept> list2 = session.selectList("com.mappers.deptmapper2.querybydeptnos",arr);
        System.out.println(list2);
        //测试入参为List类型
        List<Dept> list3 = session.selectList("com.mappers.deptmapper2.querybynos",List.of(10,20));
        System.out.println(list3);
        //测试入参为Map类型
        Map<String,Object> map = new HashMap<>();
        map.put("dname","RESEARCH");
        map.put("loc","NEW YORK");
        List<Dept> list4 = session.selectList("com.mappers.deptmapper2.querybynoorname",map);
        System.out.println(list4);
        session.close();
    }
}

定义Emp类javabean:

private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Integer sal;
private Integer comm;
private Integer deptno;

empmapper(sql映射文件):



<mapper namespace="com.mappers.empmapper">
    
    <select id="queryallbyhiredate" parameterType="date" resultType="Emp">
        select * from emp where hiredate = #{hiredate}
    select>
    
    <select id="querysalbyempno" parameterType="int" resultType="int">
        select sal from emp where empno = #{empno}
    select>
    
    <select id="queryenamebynamelike" parameterType="string" resultType="string">
        select ename from emp where ename like '%'||#{ename}||'%'
    select>
    
    <select id="queryhiredatebyempno" parameterType="int" resultType="date">
        select hiredate from emp where empno = #{empno}
    select>
    
    <select id="queryenameandsalbyempno" parameterType="int" resultType="Emp">
        select ename,sal from emp where empno = #{empno}
    select>
    
    <select id="queryallbyempno" parameterType="int" resultType="map">
        select * from emp where empno = #{empno}
    select>
    
    <select id="queryallbydeptno" parameterType="int" resultType="map">
        select * from emp where deptno = #{deptno}
    select>
mapper>

测试代码:

import com.pojo.Emp;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class TestEmp01 {
     
    public static void main(String[] args) throws IOException, ParseException {
     
        SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml")).openSession();
        //测试入参类型为Date类型
        List<Emp> list = session.selectList("com.mappers.empmapper.queryallbyhiredate",new SimpleDateFormat("yyyy/MM/dd").parse("1981/12/3"));
        list.forEach(System.out::println);
        //测试结果类型为基本数据类型或其包装类
        int sal = session.selectOne("com.mappers.empmapper.querysalbyempno",7566);
        System.out.println(sal);
        //测试结果类型为String
        List<String> list2 = session.selectList("com.mappers.empmapper.queryenamebynamelike","A");
        list2.forEach(System.out::println);
        //测试结果类型为Date
        Date date = session.selectOne("com.mappers.empmapper.queryhiredatebyempno",7566);
        System.out.println(date);
        //测试结果类型为javabean
        Emp e1 = session.selectOne("com.mappers.empmapper.queryenameandsalbyempno",7566);
        System.out.println(e1);
        //测试结果类型为Map类型
        Map<String,Object> map = session.selectOne("com.mappers.empmapper.queryallbyempno",7839);
        System.out.println(map);
        //测试结果为List类型
        List<Map<String,Object>> list3 = session.selectList("com.mappers.empmapper.queryallbydeptno",20);
        list3.forEach(System.out::println);
        session.close();
    }
}

4. 增删改操作

deptmapper3(sql映射文件):




<mapper namespace="com.mappers.deptmapper3">
    
    <insert id="insertdept" parameterType="dept">
        insert into dept values (#{deptno},#{dname},#{loc})
    insert>
    
    <update id="updatedept" parameterType="string">
        update dept set loc = #{loc} where deptno=80
    update>
    
    <delete id="deletedept" parameterType="int">
        delete from dept where deptno = #{deptno}
    delete>
mapper>

测试代码:

import com.pojo.Dept;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;

public class TestDept03 {
     
    public static void main(String[] args) throws IOException {
     
        SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml")).openSession(true);//自动提交事务
        //测试添加数据
        int row = session.update("com.mappers.deptmapper3.insertdept",new Dept(80,"bbbb","shanghai"));
        if (row>0){
     
            System.out.println("添加成功");
        }else {
     
            System.out.println("添加失败");
        }
        //测试修改数据
        int row2 = session.update("com.mappers.deptmapper3.updatedept","beijing");
        if (row2>0){
     
            System.out.println("修改成功");
        }else {
     
            System.out.println("修改失败");
        }
        //测试删除数据
        int row3 = session.update("com.mappers.deptmapper3.deletedept",80);
        if (row3>0){
     
            System.out.println("删除成功");
        }else {
     
            System.out.println("删除失败");
        }
        session.close();
    }
}

5. Log4J日志

日志分为五个级别:DEBUG(人为调试信息)、INFO(普通信息)、WARN(警告)、ERROR(错误) 和 FATAL(系统错误)

这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL,分别用来指定这条日志信息的重要程度,Log4j的规则是只输出级别不低于设定级别的日志信息,假设Loggers级别设定为INFO,则INFO、WARN、ERROR和FATAL级别的日志信息都会输出,而级别比INFO低的DEBUG则不会输出。

Log4J配置文件:

# Set root category priority to INFO and its only appender to CONSOLE.
# 输出到控制台(普通语句执行是不输出debug日志)
# 提高整体日志级别为ERROR
log4j.rootCategory=ERROR, CONSOLE
# 单独设置SQL语句的输出级别为DEBUG级别
# 包级别
log4j.logger.com.mappers=DEBUG
# 输出到控制台和日志文件
#log4j.rootCategory=INFO, CONSOLE, LOGFILE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %m%n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
# 日志文件路径
log4j.appender.LOGFILE.File=E:/java code/log4j/log4j.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %m %l%n

6. 接口绑定

Myabtis中,提供了一套接口绑定方案,程序员可以提供一个接口,然后提供一个与接口所对应的SQL映射文件,Myabaits会自动将接口与xml文件进行绑定。根据接口和对应的xml文件会创建一个接口的实现类和对象,方便方法的调用。

SQL映射文件与指定接口绑定的规则:

  • SQL映射文件需要与接口同包同名
  • SQL映射文件命名空间namespace是它所绑定的接口的包名.类名
  • SQL标签的id与接口中对应的抽象方法的方法名相同
  • SQL标签参数类型与返回值类型与抽象方法的相同

mybatis配置文件:





<configuration>
    
    <properties resource="db.properties" />

    
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    settings>

    <typeAliases>
        <package name="com.pojo"/> 
    typeAliases>

    <environments default="dev">
        
        <environment id="dev">
            <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>
        
        <package name="com.mappers"/>
    mappers>
configuration>

封装工具类获得SqlSession:

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 java.io.IOException;

//获取会话的工具类
public class SessionUtils {
     
    //factory-> SqlSessionFactory是单例的
    private static SqlSessionFactory factory = null;

    static {
     
        try {
     
            factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml"));
        } catch (IOException e) {
     
            e.printStackTrace();
        }
    }

    //获取会话
    public static SqlSession getSession(){
     
        SqlSession session = null;
        if(factory!=null){
     
            session = factory.openSession(true);  //自动提交
        }
        return session;
    }
}

6.1 接口绑定方案实现增删查改

定义接口:

import org.apache.ibatis.annotations.Param;
import java.util.List;

public interface EmpMapper {
     
    //测试不传参数
    List<Emp> queryAllEmp();
    //测试传入一个参数
    Emp queryAllbyEmpno(int empno);
    //测试传入两个相同类型的参数
    List<Emp> queryAllbydeptnoandsal(int deptno,int sal);
    //测试传入两个不同类型的参数
    List<Emp> queryAllbyjobandsal(@Param("job") String job, @Param("sal") int sal);
    //测试增加数据
    int insertEmp(@Param("empno") int empno,@Param("ename") String ename,@Param("sal") int sal);
    //测试修改数据
    int updateEmp(@Param("sal") int sal,@Param("empno") int empno);
    //测试删除数据
    int deleteEmp(@Param("empno") int empno);
}

绑定的sql映射文件:




<mapper namespace="com.mappers.EmpMapper">
    
    <select id="queryAllEmp" resultType="emp">
        select * from emp
    select>
    
    <select id="queryAllbyEmpno" parameterType="int" resultType="emp">
        select * from emp where empno = #{param1}
    select>
    
    <select id="queryAllbydeptnoandsal" resultType="emp">
        select * from emp where deptno=#{param1} and sal>#{param2}
    select>
    
    <select id="queryAllbyjobandsal" resultType="emp">
        select * from emp where job=#{job} and sal>=#{sal}
    select>
    
    <insert id="insertEmp">
        insert into emp(empno,ename,sal) values(#{empno},#{ename},#{sal})
    insert>
    
    <update id="updateEmp">
        update emp set sal=#{sal} where empno=#{empno}
    update>
    
    <delete id="deleteEmp">
        delete from emp where empno=#{empno}
    delete>
mapper>

测试代码:

import com.mappers.EmpMapper;
import com.pojo.Emp;
import com.utils.SessionUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
//测试接口绑定方案的使用
public class EmpTest01 {
     
    public static void main(String[] args) {
     
        //1.获取会话
        SqlSession session = SessionUtils.getSession();
        //2.获取接口的实现类对象
        EmpMapper empMapper = session.getMapper(EmpMapper.class);
        //3.调用方法
        //测试不传参数
        List<Emp> list = empMapper.queryAllEmp();
        list.forEach(System.out::println);
        //测试传入一个参数
        Emp e = empMapper.queryAllbyEmpno(7839);
        System.out.println(e);
        //测试传入两个相同类型的参数
        List<Emp> list1 = empMapper.queryAllbydeptnoandsal(20,1000);
        list1.forEach(System.out::println);
        //测试传入两个不同类型的参数
        List<Emp> list2 = empMapper.queryAllbyjobandsal("SALESMAN",1500);
        list2.forEach(System.out::println);
        //测试增加数据
        int row1 = empMapper.insertEmp(9999,"zhangsan",10000);
        System.out.println(row1>0?"添加成功":"添加失败");
        //测试修改数据
        int row2 = empMapper.updateEmp(5000,9999);
        System.out.println(row2>0?"修改成功":"修改失败");
        //测试删除数据
        int row3 = empMapper.deleteEmp(9999);
        System.out.println(row3>0?"删除成功":"删除失败");
        //4.关闭
        session.close();
    }
}

6.2 接口绑定方案实现增删改批量操作

定义接口:

import com.pojo.Emp;
import java.util.List;

public interface EmpMapper2 {
     
    //批量添加数据
    int insertEmpSome(List<Emp> list);
    //批量修改数据
    int updateEmpSome(List<Emp> list);
    //批量删除数据
    int deleteEmpSome(List<Integer> list);
}

绑定的sql映射文件:




<mapper namespace="com.mappers.EmpMapper2">
    
    <insert id="insertEmpSome">
         insert into emp(empno,ename,sal)
         <foreach collection="list" item="item" separator="union">
             select #{item.empno},#{item.ename},#{item.sal} from dual
         foreach>
    insert>
    
    <update id="updateEmpSome">
        begin
        <foreach collection="list" item="item" separator=";">
            update emp set sal=#{item.sal} where empno=#{item.empno}
        foreach>
        ;end;
    update>
    
    <delete id="deleteEmpSome">
        delete from emp where empno in
        <foreach collection="list" item="item" separator="," open="(" close=")">
            #{item}
        foreach>
    delete>
mapper>

测试代码:

import com.mappers.EmpMapper2;
import com.pojo.Emp;
import com.utils.SessionUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class EmpTest02 {
     
    public static void main(String[] args) {
     
        SqlSession session = SessionUtils.getSession();
        EmpMapper2 empMapper = session.getMapper(EmpMapper2.class);
        //测试批量添加数据
        empMapper.insertEmpSome(List.of(
                new Emp(1111,"张三",10000),
                new Emp(2222,"李四",20000),
                new Emp(3333,"王五",30000)
        ));
        //测试批量修改数据
        empMapper.updateEmpSome(List.of(
                new Emp(1111,15000),
                new Emp(2222,25000)
        ));
        //测试批量删除数据
        empMapper.deleteEmpSome(List.of(1111,2222,3333));
        session.close();
    }
}

7. 动态SQL

7.1 if

用于进行条件判断,test 属性用于指定判断条件,为了拼接条件, 在 SQL 语句后强行添加 1=1 的恒成立条件

<select id="sel" resultType="user">
    select * from t_user where 1=1
    <if test="username != null and username != ''"> 
        and username=#{username}
    if>
    <if test="password != null and password != ''"> 
        and password=#{password}
    if>
select>

7.2 where

用于管理 where 子句,有如下功能:

  • 如果没有条件,不会生成where关键字
  • 如果有条件,会自动添加where关键字
  • 如果第一个条件中有and,会被去除
<select id="sel" resultType="user">
    select * from t_user
    <where>
        <if test="username != null and username != ''"> 
            and username=#{username}
        if>
        <if test="password != null and password != ''"> 
            and password=#{password}
        if>
    where>
select>

7.3 choose…when…otherwise

功能类似于javase中的switch…case…语句

<select id="sel" resultType="user">
    select * from t_user
    <where>
        <choose>
            <when test="username != null and username != ''">
                and username = #{username}
            when>
            <when test="password != null and password != ''">
                and password = #{password}
            when>
            <otherwise> and 1=1 otherwise>
        choose>
    where>
select>

7.4 set

用于维护update语句中的set语句,功能如下:

  • 满足条件时,会自动添加set关键字
  • 会去除多余的逗号
  • 不满足条件时,不会生成set关键字
<update id="updUser" parameterType="user">
    update t_user
    <set>
        id=#{id},
        <if test="username != null and username != ''">
            username=#{username},
        if>
        <if test="password != null and password != ''">
            password=#{password},
        if>
    set>
    where id=#{id}
update>

7.5 trim

用于在前后添加或删除一些内容,功能如下:

  • prefix:在前面添加内容
  • prefixOverrides:从前面去除内容
  • suffix:向后面添加内容
  • suffixOverrides:从后面去除内容
<update id="updUser" parameterType="user">
    update t_user
    
    <trim prefix="set" prefixOverrides="user" suffix="hahaha"
          suffixOverrides=","> username=#{username},
    trim>
    where id=#{id}
update>

7.6 bind

对于数据进行再加工,一般用于模糊查询

<select id="sel" resultType="user">
    select * from t_user
    <where>
        <if test="username!=null and username!=''">
            <bind name="username" value="'%' + username + '%'" />
            and username like #{username}
        if>
    where>
select>

7.7 foreach

用于在SQL语句中遍历集合参数,在in查询中使用:

  • collection:待遍历的集合
  • open:设置开始符号
  • item:迭代变量
  • separator:项目分隔符
  • close:设置结束符

7.8 sql…include

用于提取SQL语句,include用于引用SQL语句

<sql id="mySql"> id, username, password sql>
<select id="selIn" parameterType="list" resultType="user">
    select
    <include refid="mySql" />
    from t_user where id in
    <foreach collection="list" open="(" separator="," close=")"
             item="item"> #{item}
    foreach>
select>

例:

定义接口:

import com.pojo.Emp;
import org.apache.ibatis.annotations.Param;
import java.util.List;

public interface EmpMapper3 {
     
    //测试where,if
    List<Emp> queryTest(@Param("empno") Integer empno, @Param("deptno") Integer deptno);
    //测试choose...when...otherwise
    List<Emp> queryTestChoose(@Param("empno") Integer empno,@Param("deptno") Integer deptno);
    //测试trim
    List<Emp> queryTestTrim(@Param("deptno") Integer deptno);
    //测试bind
    List<Emp> queryEmpLike(@Param("s") String s);
}

绑定的sql映射文件:




<mapper namespace="com.mappers.EmpMapper3">
    
    
    <sql id="allField">
        empno,ename,mgr,hiredate,sal,comm,deptno
    sql>
    
    <select id="queryTest" resultType="emp">
        select <include refid="allField"/> from emp
        <where>
            <if test="empno!=null and empno!=0">
                and empno=#{empno}
            if>
            <if test="deptno!=null and deptno!=0">
                and deptno=#{deptno}
            if>
        where>
    select>
    
    <select id="queryTestChoose" resultType="emp">
        select <include refid="allField"/> from emp
        <where>
            <choose>
                <when test="empno!=null and empno!=0">
                    and empno=#{empno}
                when>
                <when test="deptno!=null and deptno!=0">
                    and deptno=#{deptno}
                when>
                <otherwise>
                    and 1=1
                otherwise>
            choose>
        where>
    select>
    
    <select id="queryTestTrim" resultType="emp">
        select <include refid="allField"/> from emp
        <trim prefix="where">
            deptno=#{deptno}
        trim>
    select>
    
    <select id="queryEmpLike" resultType="emp">
        select <include refid="allField"/> from emp
        <trim prefix="where">
        <bind name="s" value="'%'+s+'%'"/>
            ename like #{s}
        trim>
    select>
mapper>

测试代码:

import com.mappers.EmpMapper3;
import com.pojo.Emp;
import com.utils.SessionUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

//测试动态SQL
public class EmpTest03 {
     
    public static void main(String[] args) {
     
        SqlSession session = SessionUtils.getSession();
        EmpMapper3 empMapper = session.getMapper(EmpMapper3.class);
        测试where,if
        List<Emp> list = empMapper.queryTest(0,0);
        list.forEach(System.out::println);
        //测试choose...when...otherwise
        List<Emp> list2 = empMapper.queryTestChoose(0,20);
        list2.forEach(System.out::println);
        //测试trim
        List<Emp> list3 = empMapper.queryTestTrim(10);
        list3.forEach(System.out::println);
        //测试bind
        List<Emp> list4 = empMapper.queryEmpLike("A");
        list4.forEach(System.out::println);
        session.close();
    }
}

8. 列名与属性名不一致问题解决方案

  • 给别名,别名为对应的成员属性名,mybatis有自动映射机制自动把列与属性匹配在一起
<select id="selAll" resultType="user">
    select id id1, username username1, password password2 from t_user
select>
  • resultMap用于自定义映射关系,可以由程序员自主制定列名和属性名的映射关系
<resultMap type="user" id="umap"> 
    <id column="id" property="id1" /> 
    <result column="username" property="username1" />
    <result column="password" property="password1" />
resultMap>
<select id="selAll" resultMap="umap"> select * from t_user select>

9. 关系映射查询

数据库中的表有着一对一,一对多,多对多等关系,如果实现表连接得到数据,需要在对应类中定义另一个类的对象为成员变量。

以Emp表与Dept表为例,每一个员工有自己的部门,一个部门有很多的员工,如果想查询部门信息及部门员工信息时就需要关系映射查询。

实现查询部门信息及部门中员工的信息:

Dept类javabean:

private Integer deptno;
private String dname;
private String loc;
private List<Emp> emps;

Emp类javabean:

private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Integer sal;
private Integer comm;
private Integer deptno;

定义接口:

import com.pojo.Dept;
import java.util.List;
public interface DeptMapper {
     
    //查询所有部门的部门信息和员工信息
    List<Dept> queryDept();
}

sql映射文件:




<mapper namespace="com.mappers.DeptMapper">
    
    <resultMap id="mymap" type="dept"> 
        <id property="deptno" column="deptno"/> 
        <result property="dname" column="dname"/> 
        <result property="loc" column="loc"/>
        
        <collection property="emps" javaType="list" ofType="emp">
            <id property="empno" column="empno"/>
            <result property="ename" column="ename"/>
            <result property="job" column="job"/>
            <result property="mgr" column="mgr"/>
            <result property="hiredate" column="hiredate"/>
            <result property="sal" column="sal"/>
            <result property="comm" column="comm"/>
            <result property="deptno" column="deptno"/>
        collection>
    resultMap>
    
    <select id="queryDept" resultMap="mymap">
        select d.deptno,d.dname,d.loc,e.empno,e.ename,e.sal,e.comm from dept d left join emp e on d.deptno=e.deptno
    select>
mapper>

测试代码:

import com.mappers.DeptMapper;
import com.pojo.Dept;
import com.utils.SessionUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class DeptTest {
     
    public static void main(String[] args) {
     
        SqlSession session = SessionUtils.getSession();
        DeptMapper mapper = session.getMapper(DeptMapper.class);
        List<Dept> list = mapper.queryDept();
        list.forEach(System.out::println);
        session.close();
    }
}

实现查询员工个人信息及其所在部门信息:

Emp类javabean:

private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Integer sal;
private Integer comm;
private Integer deptno;
private Dept dept;

Dept类javabean:

private Integer deptno;
private String dname;
private String loc;

定义接口:

import com.pojo.Emp;
import java.util.List;
//查询所有员工的个人信息及其所在部门信息
public interface EmpMapper {
     
    List<Emp> queryEmp();
}

sql映射文件:




<mapper namespace="com.mappers.EmpMapper">
    <resultMap id="mymap" type="emp">
        <id property="empno" column="empno"/>
        <result property="ename" column="ename"/>
        <result property="job" column="job"/>
        <result property="mgr" column="mgr"/>
        <result property="hiredate" column="hiredate"/>
        <result property="sal" column="sal"/>
        <result property="comm" column="comm"/>
        <result property="deptno" column="deptno"/>
        
        <association property="dept" javaType="dept">
            <id property="deptno" column="deptno"/>
            <result property="dname" column="dname"/>
            <result property="loc" column="loc"/>
        association>
    resultMap>
    <select id="queryEmp" resultMap="mymap">
        select e.empno,e.ename,e.job,e.mgr,e.sal,e.comm,d.deptno,d.dname,d.loc from emp e join dept d on e.deptno=d.deptno
    select>
mapper>

测试代码:

import com.mappers.EmpMapper;
import com.pojo.Emp;
import com.utils.SessionUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class EmpTest {
     
    public static void main(String[] args) {
     
        SqlSession session = SessionUtils.getSession();
        EmpMapper mapper = session.getMapper(EmpMapper.class);
        List<Emp> list = mapper.queryEmp();
        list.forEach(System.out::println);
        session.close();
    }
}

10. Mybatis缓存机制

10.1 一级缓存

  • 默认开启,线程级别的缓存,SqlSession 的缓存
  • 在一个 SqlSession 生命周期中有效,SqlSession 关闭,缓存清空
  • 在同一个 SqlSession 中,Mybatis会把执行的方法和参数通过算法生成缓存的键值,将键值和结果存放在一个 Map 中,如果后续的键值一样,则直接从 Map 中获取数据
  • 不同的 SqlSession 之间的缓存是相互隔离的
  • 用一个 SqlSession,可以通过配置使得在查询前清空缓存,flushCache=“true”
  • 任何的增删改语句都会清空缓存

10.2 二级缓存

  • 进程级别的缓存,SqlSessionFactory 的缓存
  • 在一个SqlSessionFactory生命周期中有效,可以在多个SqlSession 生命中期中共享
  • 默认关闭,需要使用的时候,配置步骤如下:
    • mybatis.xml文件setting设置中设置cacheEnabled为true
    • 对应映射文件namespace下设置cache标签
    • 对应javabean实现Serializable接口
  • 由于在更新时会刷新缓存,因此需要注意使用场合:查询频率很高,更新频率很低时使用
  • 缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响,但刷新缓存是刷新整个namespace 的缓存
  • 最好在 「只有单表操作」 的表的 namespace 使用缓存, 而且对该表的操作都在这个 namespace中,否则可能会出现数据不一致的情况

二级缓存的应用场景:对于访问多的查询请求并且用户对查询结果实时性要求不高的情况下,可采用mybatis二级缓存,降低数据库访问量,提高访问速度,根据需求可以在cache标签后设置相应的flushInterval(刷新间隔时间),单位为ms

二级缓存的失效条件:

  • Sqlsession不调用close方法就无法将数据写入缓存
  • 增删改操作会刷新缓存

11. 注解开发

11.1 增删改查注解

  • @Select: 类似于select标签
  • @Insert: 类似于insert标签
  • @Update: 类似于update标签
  • @Delete: 类似于delete标签

定义接口:

import com.pojo.Emp;
import org.apache.ibatis.annotations.*;
import java.util.List;

public interface EmpMapper {
     
    //Select注解
    @Select("select * from emp")
    List<Emp> queryAll();
    @Select("select * from emp where deptno=#{deptno} and sal>=#{sal}")
    List<Emp> queryAllByDeptnoSal(@Param("deptno") Integer deptno,@Param("sal") Integer sal);
    //Insert注解
    @Insert("insert into emp(empno,ename,sal) values(#{empno},#{ename},#{sal})")
    int insertEmp(Emp e);
    //Update注解
    @Update("update emp set sal=#{sal} where empno=#{empno}")
    int updateEmp(@Param("sal") Integer sal,@Param("empno") Integer empno);
    //Delete注解
    @Delete("delete from emp where ename=#{ename}")
    int deleteEmp(@Param("ename") String ename);
}

测试代码:

import com.mappers.EmpMapper;
import com.pojo.Emp;
import com.utils.SessionUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class EmpTest {
     
    public static void main(String[] args) {
     
        SqlSession session = SessionUtils.getSession();
        EmpMapper mapper = session.getMapper(EmpMapper.class);
        //测试Select注解
        List<Emp> list1 = mapper.queryAll();
        list1.forEach(System.out::println);
        List<Emp> list2 = mapper.queryAllByDeptnoSal(30,1500);
        list2.forEach(System.out::println);
        //测试Insert注解
        int row1 = mapper.insertEmp(new Emp(9999,"张三",10000));
        System.out.println(row1>0?"添加成功":"添加失败");
        //测试Update注解
        int row2 = mapper.updateEmp(15000,9999);
        System.out.println(row2>0?"修改成功":"修改失败");
        //测试Delete注解
        int row3 = mapper.deleteEmp("张三");
        System.out.println(row3>0?"删除成功":"删除失败");
        session.close();
    }
}

11.2 关系映射注解

  • @Results: 类似于resultMap标签
  • @Result: 类似resultMap的子标签
  • @One: 类似于association标签
  • @Many: 类似于collection标签

代码:

测试One注解:

定义接口:

//测试One注解
import com.pojo.Dept;
import com.pojo.Emp;
import org.apache.ibatis.annotations.*;
import java.util.List;

public interface EmpMapper {
     
    @Select("select deptno,dname,loc from dept where deptno=#{deptno}")
    List<Dept> queryDept(@Param("deptno") Integer deptno);

    @Select("select empno,ename,sal,deptno from emp")
    @Results(value = {
     
            @Result(property = "empno",column = "empno",id = true),
            @Result(property = "ename",column = "ename"),
            @Result(property = "sal",column = "sal"),
            @Result(property = "deptno",column = "deptno"),
            @Result(property = "dept",one = @One(select = "com.mappers.EmpMapper.queryDept"),column = "deptno")
    })
    List<Emp> queryAllEmp();
}

测试代码:

//测试One注解
import com.mappers.EmpMapper;
import com.pojo.Emp;
import com.utils.SessionUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class EmpTest {
     
    public static void main(String[] args) {
     
        SqlSession session = SessionUtils.getSession();
        EmpMapper mapper = session.getMapper(EmpMapper.class);
        List<Emp> list = mapper.queryAllEmp();
        list.forEach(System.out::println);
        session.close();
    }
}

测试Many注解:

定义接口:

//测试Many注解
import com.pojo.Dept;
import com.pojo.Emp;
import org.apache.ibatis.annotations.*;
import java.util.List;

public interface DeptMapper {
     
    @Select("select * from emp where deptno=#{deptno}")
    List<Emp> queryEmpByDeptno(@Param("deptno") Integer deptno);

    @Select("select * from dept")
    @Results(value = {
     
            @Result(property = "deptno",column = "deptno",id = true),
            @Result(property = "dname",column = "dname"),
            @Result(property = "loc",column = "loc"),
            @Result(property = "emps",many = @Many(select = "com.mappers.DeptMapper.queryEmpByDeptno"),column = "deptno")
    })
    List<Dept> queryAllDept();
}

测试代码:

测试Many注解
import com.mappers.DeptMapper;
import com.pojo.Dept;
import com.utils.SessionUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class DeptTest {
     
    public static void main(String[] args) {
     
        SqlSession session = SessionUtils.getSession();
        DeptMapper mapper = session.getMapper(DeptMapper.class);
        List<Dept> list = mapper.queryAllDept();
        list.forEach(System.out::println);
        session.close();
    }
}

12. 逆向工程

mybatis-generator是一款mybatis自动代码生成工具,可以通过配置,快速生成pojo,mapper和xml文件。

官网地址:http://mybatis.org/generator/configreference/xmlconfig.html

generatorConfig.xml文件:



<generatorConfiguration>
    
    <properties resource="db.properties" />
    
    <context id="Tables" targetRuntime="MyBatis3">
        
        <property name="javaFileEncoding" value="UTF-8" />
        
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
        <commentGenerator>
            <property name="suppressDate" value="true" />
            
            <property name="suppressAllComments" value="false" />
        commentGenerator>
        
        <jdbcConnection
                driverClass="${driver}"
                connectionURL="${url}"
                userId="${username}"
                password="${password}">
        jdbcConnection>
        
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        javaTypeResolver>
        
        <javaModelGenerator targetPackage="com.pojo"
                            targetProject="E:\java code\javaworkspace\mybatis05\src">
            <property name="constructorBased" value="true"/>
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        javaModelGenerator>
        
        <sqlMapGenerator targetPackage="com.mappers"
                         targetProject="E:\java code\javaworkspace\mybatis05\src">
            <property name="enableSubPackages" value="true" />
        sqlMapGenerator>
        
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.mappers" targetProject="E:\java code\javaworkspace\mybatis05\src">
            <property name="enableSubPackages" value="true" />
        javaClientGenerator>
        
        <table tableName="dept" domainObjectName="Dept"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">table>
        <table tableName="emp" domainObjectName="Emp"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
            <columnOverride column="empno" javaType="Integer"/>
        table>
    context>
generatorConfiguration>

启动代码:

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class Util {
     
    public static void main(String[] args) throws Exception {
     
        List<String> warnings = new ArrayList<>();
        boolean overwrite = true;
        try {
     
            //指定 逆向工程配置文件
            File configFile = new File("src/generatorConfig.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);
        } catch (Exception e) {
     
            e.printStackTrace();
        }
    }
}

你可能感兴趣的:(数据库,java,mybatis,数据库)