Java经典框架之MyBatis

MyBatis

Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。
  

课程内容的介绍

1. 基本使用介绍
2. 配置文件详解
3. 映射文件详解
4. 动态SQL语句
5. 延迟加载和缓存处理
6. MyBatis和Spring的整合操作
7. MyBatis的逆向工程
  

一、MyBatis的基本使用

官网地址:https://mybatis.org/mybatis-3/zh/index.html
   
1. 什么是 MyBatis ?
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
     
2. Mybatis和hibernate的比较对象
关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping)。

Java经典框架之MyBatis_第1张图片

    
3.MyBatis的基本使用
3.1 创建Maven项目添加对应的依赖
首先肯定要添加MyBatis的依赖,然后要操作MySQL数据库中的表结构,所以我们需要添加MYSQL的驱动依赖。

    
    
        org.mybatis
        mybatis
        3.5.1
    
    
    
        mysql
        mysql-connector-java
        8.0.11
    
    
3.2 创建全局配置文件
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。后面会再探讨 XML 配置文件的详细内容,这里先给出一个简单的示例。



    
        
            
            
                
                
                
                
            
        
    
    
        
    
     
3.3 定义User对象
我们将MyBatis是一个ORM框架,那么会将数据库中的user表中的数据映射为Java中的对象,所以我们需要创建该对象与之对应。
package com.bobo.pojo;

/**
 * 多列操作数据
 *    按住Alt键 鼠标操作
 */
public class User {

  private Integer id;
  private String username;
  private String address;
  private String gender ;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public User() {
    }

    public User(Integer id, String username, String address, String gender) {
        this.id = id;
        this.username = username;
        this.address = address;
        this.gender = gender;
    }

    public User(String username, String address, String gender) {
        this.username = username;
        this.address = address;
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }
}
      
3.4 创建映射文件
MyBatis要操作数据库,那么我们需要在映射文件中来写SQL语句。



    
    
        insert into t_user (username,address,gender)values(#{username},#{address},#{gender})
    
        
3.5 将映射文件关联配置文件
上面的操作中映射文件和配置文件是没有关联的,我们需要在主配置文件中添加相关的信息。



    
        
            
            
                
                
                
                
            
        
    
    
        
        
    

     

3.6 测试代码运行
测试代码
/**
     * MyBatis案例
     */
   @Test
    public void test01() throws Exception{
        // 1.读取核心配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        // 2.获取一个SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3.获取一个SqlSession对象 基于SqlSessionFactory获取
        SqlSession sqlSession = factory.openSession();
        // 添加数据 ORM框架 面试对象操作
        User user = new User("翠花","深圳福田","2");
        // 4.执行数据库操作 statement= namespace+"."+id
        int count = sqlSession.insert("com.bobo.pojo.User.addUser", user);
        System.out.println("影响的行数..."+count);
    }
   
在Maven项目中默认的src/main/java目录下面只会打包java编译后的class文件,所以对于的UserMapper.xml文件是不会打包进去的。

Java经典框架之MyBatis_第2张图片

  
出现这种情况我们需要在pom文件中特别指出要处理的资源文件。
    
        
            
                src/main/java
                
                    **/*.xml
                
                true
            
        
    
   
重启后又出现了新的错误 。

Java经典框架之MyBatis_第3张图片

     
之前在Spring中的JdbcTemplate中就遇到过,是在jdbc的url中缺少时区的制订
jdbc:mysql://localhost:3306/shop?
serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
   
运行测试程序,没有报错。

Java经典框架之MyBatis_第4张图片

  
但是数据库中并没有数据。

Java经典框架之MyBatis_第5张图片

   
我们需要手动的提交数据。
    /**
     * MyBatis案例
     */
   @Test
    public void test01() throws Exception{
        // 1.读取核心配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        // 2.获取一个SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3.获取一个SqlSession对象 基于SqlSessionFactory获取
        SqlSession sqlSession = factory.openSession();
        // 添加数据 ORM框架 面试对象操作
        User user = new User("翠花","深圳福田","2");
        // 4.执行数据库操作 statement= namespace+"."+id
        int count = sqlSession.insert("com.bobo.pojo.User.addUser", user);
        System.out.println("影响的行数..."+count);
        // 5.MyBatis中默认是不会自动提交DML操作的数据的
       sqlSession.commit();
       // 6.关闭会话
       sqlSession.commit();
    }

       

然后执行数据就进入数据库中了。

Java经典框架之MyBatis_第6张图片

       
4.修改、删除和查询操作
4.1 映射文件



    
    
        insert into t_user (username,address,gender)values(#{username},#{address},#{gender})
    
    
    
        update t_user set username=#{username} ,address=#{address},gender=#{gender} where id =#{id}
    
    
    
        delete from t_user where id=#{id}
    
    
    
    
    
      
4.2 测试代码
package com.bobo.test;

import com.bobo.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;


import java.io.InputStream;
import java.util.List;

public class TestDemo01 {

    /**
     * MyBatis案例
     */
   @Test
    public void test01() throws Exception{
        // 1.读取核心配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        // 2.获取一个SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3.获取一个SqlSession对象 基于SqlSessionFactory获取
        SqlSession sqlSession = factory.openSession();
        // 添加数据 ORM框架 面试对象操作
        User user = new User("翠花","深圳福田","2");
        // 4.执行数据库操作 statement= namespace+"."+id
        int count = sqlSession.insert("com.bobo.pojo.User.addUser", user);
        System.out.println("影响的行数..."+count);
        // 5.MyBatis中默认是不会自动提交DML操作的数据的
       sqlSession.commit();
       // 6.关闭会话
       sqlSession.commit();
    }

    @Test
    public void test02() throws Exception{
       InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
       SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession sqlSession = factory.openSession();
        User user = new User(19,"翠花","北京海淀","女");
        int i = sqlSession.update("com.bobo.pojo.User.updateUser", user);
        System.out.println("影响的行数:" + i);
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void deleteUser() throws Exception{
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession sqlSession = factory.openSession();
        int i = sqlSession.delete("com.bobo.pojo.User.deleteUser", 20);
        System.out.println("影响的行数:" + i);
        sqlSession.commit();
        sqlSession.close();

    }
    @Test
    public void queryAll() throws Exception{
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession sqlSession = factory.openSession();
        List lists = sqlSession.selectList("com.bobo.pojo.User.queryAll");
        for (User user : lists) {
            System.out.println(user);
        }
        sqlSession.close();

    }

    @Test
    public void queryById() throws Exception{
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        SqlSession sqlSession = factory.openSession();
        List lists = sqlSession.selectList("com.bobo.pojo.User.queryById",19);
        for (User user : lists) {
            System.out.println(user);
        }
        sqlSession.close();

    }
}
    
5.案例优化
通过上面的效果演示大家会发现每个案例都有很多的重复代码。完全可以简化操作。

Java经典框架之MyBatis_第7张图片

    
单独提供SqlSessionFactory单例方法。
package com.bobo.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;
import java.util.Date;

/**
 * 工具类
 *    对外提供SqlSessionFactory的单例对象
 */
public class DbUtils {

    private static SqlSessionFactory factory;

    public static SqlSessionFactory getInstance(){
        if(factory == null){
            InputStream in = null;
            try{
                in = Resources.getResourceAsStream("mybatis-cfg.xml");
            }catch (Exception e){
                e.printStackTrace();
            }
            synchronized (DbUtils.class){
                if(factory == null){
                    factory = new SqlSessionFactoryBuilder().build(in);
                }
            }
        }
        return factory;
    }

}
      
声明接口及实现类
package com.bobo.dao;

import com.bobo.pojo.User;

import java.util.List;

public interface IUserDao {

    int  addUser(User user);
    int  updateUser(User user);
    int  deleteUser(Integer id);
    List queryById(Integer id);

}
package com.bobo.dao.impl;

import com.bobo.pojo.User;
import com.bobo.dao.IUserDao;
import com.bobo.utils.DbUtils;

import java.util.List;

public class UserDaoImpl implements IUserDao {

    @Override
    public int addUser(User user) {
        return DbUtils.getInstance().openSession().insert("com.bobo.dao.IUserDao.addUser",user);
    }

    @Override
    public int updateUser(User user) {
        return DbUtils.getInstance().openSession().insert("com.bobo.dao.IUserDao.updateUser",user);
    }

    @Override
    public int deleteUser(Integer id) {
        return DbUtils.getInstance().openSession().insert("com.bobo.dao.IUserDao.updateUser",id);
    }

    @Override
    public List queryById(Integer id) {
        return DbUtils.getInstance().openSession().selectList("com.bobo.dao.IUserDao.queryById", id);
    }
}
   
可以发现Dao实现类中的方法是实现是有很多可以相互约定的操作,如果相互都按照约定来执行的话,那么我们完全可以省略掉Dao的实现类,通过代理对象来实现。
@Test
    public void test03(){
       // 获取一个Dao接口的代理对象
        IUserDao  dao = (IUserDao) Proxy.newProxyInstance(IUserDao.class.getClassLoader()
                , new Class[]{IUserDao.class}
                , new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println(IUserDao.class.getName()+"." + method.getName());
                        return DbUtils
                                .getInstance()
                                .openSession()
                                .selectList(IUserDao.class.getName()+"." + method.getName(),args[0]);
                    }
                });

        // dao.addUser(null);
        //dao.updateUser(null);
        List list = dao.queryById(18);
        for (User user : list) {
            System.out.println(user);
        }

    }
     

Java经典框架之MyBatis_第8张图片

     
6.基于接口的使用方式
通过前面UserDao的设计,可以发现,UserDao中的代码都是模板化代码,都可以通过配置的方式自动来生成,因此在实际开发中我们可以通过Mapper的方式来实现,具体如下:
   
6.1 声明Mapper接口
我们只需要创建相关的接口,不用创建对应的实现类。
package com.bobo.dao;

import com.bobo.pojo.User;

/**
 * Dao的接口
 */
public interface UserMapper {

    int addUser(User user);
}
  
6.2 创建映射文件
在映射文件中添加SQL操作。



    
    
        insert into t_user (username,address,gender)values(#{username},#{address},#{gender})
    
   
6.3 全局配置文件




    
    
        
            
            
                
                
                
                
            
        
    
    

        
    
   
6.4 测试
package com.bobo;

import com.bobo.dao.UserMapper;
import com.bobo.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

public class AppStart {
    public static void main(String[] args) throws Exception{
        // 1.加载全局配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        // 2.获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        // 3.根据SqlSessionFactory获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = new User("张三","广州","男");
        // 通过SqlSession获取Dao接口的代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.addUser(user);

        // 5.提交资源并关闭连接
        sqlSession.commit();
        sqlSession.close();
    }
}
  

Java经典框架之MyBatis_第9张图片

    
6.5 基于接口方式补充说明
基于接口的使用方式我们是有约定的,如果不按照该约定执行的话那么是会出问题的。
使用mapper接口方式必须满足:

Java经典框架之MyBatis_第10张图片

     

二、全局配置文件

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下。
configuration 配置
    properties 属性
    settings 设置
    typeAliases 类型别名
    typeHandlers 类型处理器
    objectFactory 对象工厂
    plugins 插件
    environments 环境
        environment 环境变量
            transactionManager 事务管理器
            dataSource 数据源
    databaseIdProvider 数据库厂商标识
    mappers 映射器
   
1.properties属性
在实际开发中我们可以面临各种各样的系统环境,为了更加灵活的切换,我们可以通过properties引入一个外部属性文件,然后在配置文件中使用即可。

Java经典框架之MyBatis_第11张图片

  
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/shop?
serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
username=root
password=123456
      
在配置文件中引入及通过EL表达式来使用。

Java经典框架之MyBatis_第12张图片

    
如果出现以下错误

Java经典框架之MyBatis_第13张图片

    
那就说明是没有把properties文件打包

Java经典框架之MyBatis_第14张图片

  
然后测试成功

Java经典框架之MyBatis_第15张图片

     
2. setting设置属性
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。

Java经典框架之MyBatis_第16张图片

  
一个完整设置

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
3.typeAlias
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书
写。
mybatis中默认提供的别名

Java经典框架之MyBatis_第17张图片

  

Java经典框架之MyBatis_第18张图片

  
执行程序

Java经典框架之MyBatis_第19张图片

  
自定义类型的别名

Java经典框架之MyBatis_第20张图片

  

Java经典框架之MyBatis_第21张图片

  

Java经典框架之MyBatis_第22张图片

    
设置了别名后,使用别名是不区分大小写的!!!

Java经典框架之MyBatis_第23张图片

  
如果我们的类型非常多,而且也需要给每个类型设置别名,那么这个工作就非常繁琐了,这时我们可以通过批量扫描自动来生成别名,具体如下:

Java经典框架之MyBatis_第24张图片

  

Java经典框架之MyBatis_第25张图片

  
4. typeHandlers
typeHandlers称为类型处理器,就是实现Java类型和数据库类型之间的转换。除了系统提供的类型转换器之外,我们也可以自定义类型转换器。我们自己实现一个 List <---> varchar之间的类型转换。
    
4.1 自定义类型转换器
package com.bobo.typehandler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

/**
 * 实现集合和Varchar之间的转换
 */
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(List.class)
public class ListVarcharTypeHandler extends BaseTypeHandler> {

    /**
     * 插入数据的时候要实现的数据转换是
     * List 转换为 字符串
     * String sql = "";
     * PreparedStatement ps = conn.createPreparedStatement(sql);
     * ps.setInt(1,14);
     * ps.setString(2,"aaa");
     * ps.setString(3,list.toString());
     * ps.setString(4,"湖南长沙");
     * 。。。
     * ps.executeUpdate();
     * 。。。
     * @param ps
     * @param i  执行的SQL语句要插入参数的位置
     * @param list 要插入的位置的数据的List类型
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, List list, JdbcType jdbcType) throws SQLException {
        System.out.println("setNonNullParameter ..... "); // a;b;c;d;
        // 处理数据 将List转换为特定格式的字符串
        StringBuffer sb = new StringBuffer();
        String msg = null;
        if(list != null){
            for (String p : list) {
                sb.append(p).append(";");
            }
            msg = sb.toString();
            msg = msg.substring(0,msg.length()-1);
        }

        // 给对应位置的占位符赋值
        ps.setString(i,msg);
    }

    /**
     * 获取非空的结果集
     * @param rs
     * @param columnName
     * @return
     * @throws SQLException
     */
    @Override
    public List getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String msg = rs.getString(columnName);
        if(msg!= null){
            return Arrays.asList(rs.getString(columnName).split(";"));
        }
        return null;

    }

    @Override
    public List getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return Arrays.asList(rs.getString(columnIndex).split(";"));
    }

    @Override
    public List getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return Arrays.asList(cs.getString(columnIndex).split(";"));
    }
}
   
4.2 映射文件修改




    
        insert into t_user (username,address,gender,favorites)values(#
{username},#{address},#{gender},#{favorites})

    

    
   
4.3 修改配置文件

Java经典框架之MyBatis_第26张图片

  
4.4 测试
添加数据

Java经典框架之MyBatis_第27张图片

   
查询数据

Java经典框架之MyBatis_第28张图片

  
5.mappers属性
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如​:


    
    
    



    
    
    



    
    
    



    
   
这些配置会告诉 MyBatis 去哪里找映射文件,剩下的细节就应该是每个 SQL 映射文件了,也就是接下来我们要讨论的。
  

三、映射文件介绍

MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
   
1. log4j
程序运行的时候我们需要通过日志来记录程序的运行情况,这些日志可以帮助我们分析程序代码及错误排查等.....
   
1.1 添加相关的依赖
        
        
            org.slf4j
            slf4j-log4j12
            1.7.25
        
   
1.2 创建log4j.properties文件
创建一个日志的属性文件,在该文件中配置日志的相关信息。
log4j.rootCategory=All, stdout , R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n

log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=D:\\logs\\qc.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
     
1.3 使用
package com.bobo;

import com.bobo.dao.UserMapper;
import com.bobo.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;

import java.io.InputStream;
import java.util.List;

public class AppStart1 {

    static Logger logger = Logger.getLogger(AppStart1.class);
    public static void main(String[] args) throws Exception{
        logger.error("log:error");
        logger.warn("log:warn");
        logger.info("log:info");
        logger.debug("log:debug");

        // 1.加载全局配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        // 2.获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        // 3.根据SqlSessionFactory获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 通过SqlSession获取Dao接口的代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List list = mapper.query(26);
        for (User user : list) {
            System.out.println(user + ":" + user.getFavorites());
        }

        // 5.提交资源并关闭连接
        sqlSession.commit();
        sqlSession.close();
    }
}
   

Java经典框架之MyBatis_第29张图片

   
2.传入参数
2.1 ${}和#{}的区别
#{}的使用方式
sql
   
执行后

Java经典框架之MyBatis_第30张图片

  
${}的使用
sql
  
执行后抛出了异常信息

Java经典框架之MyBatis_第31张图片

   
${}的使用我们必须在接口的形参中添加 @Param 注解修饰。
  
public interface UserMapper {
    int addUser(User user);
    List query(@Param("id") Integer id);
}
  
再执行就可以了

Java经典框架之MyBatis_第32张图片

  
通过日志文件可以看到两种方式执行的SQL语句是有区别的,一种是使用了占位符,一种是直接赋值的。
由于MyBatis底层还是Jdbc操作,而Jdbc操作数据库传递数据时有两种方式,一种是Statement,还一种是PreparedStatement方式,使用Statement会有SQL注入的风险,而PreparedStatement通过占位符的方式就可以避免SQL注入的情况。
在MyBatis中对应的两种使用方式的体现就是#{}和${}的方式,显然#{}对应的是PreparedStatement,而${}对应的是Statement。显然在MyBatis中我们更加推荐使用#{}。
  
2.2 多个参数
定义update标签

    update t_user set username = #{username} where id = #{id}
  
定义的接口
package com.bobo.dao;

import com.bobo.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * Dao的接口
 */
public interface UserMapper {

    int addUser(User user);

    List query(@Param("id") Integer id);

    int updateUser(String userName,Integer id);

}
  
测试 执行
package com.bobo;

import com.bobo.dao.UserMapper;
import com.bobo.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;
import java.util.Arrays;

public class AppStart3 {
    public static void main(String[] args) throws Exception{
        // 1.加载全局配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
        // 2.获取SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        // 3.根据SqlSessionFactory获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();


        // 通过SqlSession获取Dao接口的代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updateUser("赵六",27);

        // 5.提交资源并关闭连接
        sqlSession.commit();
        sqlSession.close();
    }
}
  

Java经典框架之MyBatis_第33张图片

   
根据错误提示我们可以在映射文件中通过 [arg1,arg0,param1,param2]来获取传递的多个参数。
  

Java经典框架之MyBatis_第34张图片

  

Java经典框架之MyBatis_第35张图片

  

Java经典框架之MyBatis_第36张图片

  
如果我不想使用系统提供的,而是自定义参数名称同样可以通过 @Param 实现。
  

Java经典框架之MyBatis_第37张图片

  

Java经典框架之MyBatis_第38张图片

  
2.3 包装对象
我们传递的是一个包装类对象,针对这种情况我们应该怎么获取相关的参数。
package com.bobo.pojo;

/**
 * 包装类
 */
public class UserWrapper {

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}
     
如果我们传递的是个包装对象,那么我们可以通过"."存取器来处理相关的情况。

Java经典框架之MyBatis_第39张图片

  

Java经典框架之MyBatis_第40张图片

  
3.返回数据
3.1 resultType
通过resultType设置操作的返回结果类型,如果返回的是基本数据类型,那么我们可以直接写Java中的基本数据类型即可。如果返回的是一个对象或者集合,并且对象中的属性和查询的字段名一一对应,那么resultType可以直接写一个对象。
  
3.2 resultMap
resultMap主要用来解决属性名和字段名不一致以及一对多、一对一查询等问题。字段名不一致时,首先可以通过取别名的方式解决。
Java经典框架之MyBatis_第41张图片
  
Java类中的属性name和表结构中的字段userName不同。

Java经典框架之MyBatis_第42张图片

    

Java经典框架之MyBatis_第43张图片

   
第一种解决方案就是添加别名。
    
   

Java经典框架之MyBatis_第44张图片

   
第二种解决方式是通过resultMap来指定表结构中的字段和Java类中的属性的对应关系。
    
        
        
        
        
        
    

    
   

Java经典框架之MyBatis_第45张图片

   
4.主键回写
一般情况下,主键的两种生成方式
1. 主键自增
2. 自定义主键(一般使用UUID)

Java经典框架之MyBatis_第46张图片

      
4.1 主键回填

    insert into t_user (username,address,gender,favorites)values(#{name},#{address},#{gender},#{favorites})
  
useGeneratedKeys:使用生成的主键。
keyProperty:将生成的主键的值保存到对象的id属性中。
  

Java经典框架之MyBatis_第47张图片

  

Java经典框架之MyBatis_第48张图片

    
4.2 selectKey
另外一种方式可以利用MySQL自带的last_insert_id() 函数来获取刚刚插入的id。

        
            select LAST_INSERT_ID()
        
        insert into t_user(username,address,gender)values(#{user.name},#{user.address},#{user.gender})
    
   

Java经典框架之MyBatis_第49张图片

   

四、动态SQL语句

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
     
1. if语句
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。
   
Dao的接口文件中
public interface UserMapper {
    List query(User user);
}
   
测试代码

Java经典框架之MyBatis_第50张图片

   

Java经典框架之MyBatis_第51张图片

     
2. where 语句
我们在写SQL语句的 where 部分的时候为了保证SQL语句的语法正确,我们会加上 1=1 表达式,如果我们不想这么写的话可以使用 标签来替代。
      

Java经典框架之MyBatis_第52张图片

    

Java经典框架之MyBatis_第53张图片

   
3. choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。


    
测试

Java经典框架之MyBatis_第54张图片

  

Java经典框架之MyBatis_第55张图片

  

Java经典框架之MyBatis_第56张图片

     
4. set语句
当我们要实现动态更新的时候会因为 , 问题而造成非常麻烦的后果,这时我们可以通过 标签来动态管理。

    update
    t_user
    
        
            username = #{username},
        
        
            address = #{address},
        
        
            gender = #{gender},
        
    
    where id = #{id}
   

Java经典框架之MyBatis_第57张图片

   

Java经典框架之MyBatis_第58张图片

    
5. trim语句
trim标记是一个格式化的标记。可以完成set或者where标记的功能。

Java经典框架之MyBatis_第59张图片

     
替代where的实现。
  
效果

Java经典框架之MyBatis_第60张图片

  

Java经典框架之MyBatis_第61张图片

    
替换 标签

    update
    t_user
    
        
            username = #{username},
        
        
            address = #{address},
        
        
            gender = #{gender},
        
    
    where id = #{id}

    update
    t_user
    
        
            ,username = #{username}
        
        
            ,address = #{address}
        
        
            ,gender = #{gender}
        
    
    where id = #{id}
   
效果

Java经典框架之MyBatis_第62张图片

     
6. foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)

Java经典框架之MyBatis_第63张图片

   
演示案例
  
Mapper接口声明
List queryByIds(@Param("ids") List ids);
   
效果

Java经典框架之MyBatis_第64张图片

  
foreach的第二种使用方式就是在批量插入数据的时候使用。

    insert into t_user (username,address) values
    
        (#{user.username},#{user.address})
    
   
接口中声明
Integer insertUser(@Param("users") List users);
  
测试

Java经典框架之MyBatis_第65张图片

   
7. bind语句
bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。
   
8. SQL代码片段
可重复使用的SQL语句代码片段。

Java经典框架之MyBatis_第66张图片

  

Java经典框架之MyBatis_第67张图片

       

五、 延迟加载和缓存

1.关联关系
关联关系:

Java经典框架之MyBatis_第68张图片

   
关联关系
一对一关系

Java经典框架之MyBatis_第69张图片

   
1对多的关联关系
左边到右边是1对多
右边到左边是1对1的关系

Java经典框架之MyBatis_第70张图片

  
多对多的关联关系
双向的一对多的关系

Java经典框架之MyBatis_第71张图片

  
在关系型数据库中,表与表之间很少是独立与其他表没关系的。所以在实际开发过程中我们会碰到很多复杂的关联关系。在此我们来分析下载mybatis中怎么处理这些关系。
    
1.1 1对1关系
我们有一张员工表(T_EMP),一张部门表(T_DEPT)。员工表中的一条记录对应于部门表中有且仅有一条记录。这就是一对一的关联关系。
CREATE TABLE `t_dept` (
    `deptid` int NOT NULL AUTO_INCREMENT,
    `dname` varchar(20) DEFAULT NULL,
    `ddesc` varchar(50) DEFAULT NULL,
    PRIMARY KEY (`deptid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

CREATE TABLE `t_emp` (
    `id` int NOT NULL AUTO_INCREMENT,
    `name` varchar(20) DEFAULT NULL,
    `age` int DEFAULT NULL,
    `deptid` int DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
   
查询每个员工的信息及对应的部门信息。
package com.bobo.pojo;

public class Emp {

    private Integer id;

    private String name;

    private Integer age;

    // 1对1关联关系的体现  一个员工对象最多有一个部门对象
    private Dept dept;

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  
部门对象
package com.bobo.pojo;

import java.util.List;

public class Dept {

    private Integer deptid;

    private String dname;

    private String ddesc;

    // 1对多 关系 1个部门包含有多个员工对象
    private List emps;

    public Integer getDeptid() {
        return deptid;
    }

    public void setDeptid(Integer deptid) {
        this.deptid = deptid;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getDdesc() {
        return ddesc;
    }

    public void setDdesc(String ddesc) {
        this.ddesc = ddesc;
    }

    public List getEmps() {
        return emps;
    }

    public void setEmps(List emps) {
        this.emps = emps;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptid=" + deptid +
                ", dname='" + dname + '\'' +
                ", ddesc='" + ddesc + '\'' +
                '}';
    }
}
    
映射文件




    
        
        
        
        
        
            
            
            
        
    

    
  
接口声明
package com.bobo.dao;

import com.bobo.pojo.Emp;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface EmpMapper {
     List queryEmp();

}
  
测试

Java经典框架之MyBatis_第72张图片

   
1.2 1对多关系
部门和员工的信息其实就是一个1对多的关联关系。

Java经典框架之MyBatis_第73张图片

  
# 查询部门信息 然后关联查询出部门中包含的相关的员工信息
SELECT
    t1.`deptid`
    ,t1.`dname`
    ,t1.`ddesc`
    ,t2.`id`
    ,t2.`name`
    ,t2.age
FROM t_dept t1
LEFT JOIN t_emp t2
ON t1.`deptid` = t2.`deptid`
   
pojo对象

Java经典框架之MyBatis_第74张图片

   
映射文件配置
    
        
        
        
            
            
            
        
    

    
   
测试

Java经典框架之MyBatis_第75张图片

  
1.3 多对多关系
双向的一对多就是多对多关系。
  
2 延迟加载
延迟查询是一对一和一对多查询的延续。
在默认的一对一和一对多中,一条SQL就能够查询到所有数据,但是,有的数据有时候一时半会用不上,例如查询员工,捎带获取员工的部门数据,但是部门数据使用的频率很低,这种时候可以使用延迟查询,首先获取到所有的员工数据,然后在需要的时候再去获取部门数据。当需要使用数据的时候才去加载既是延迟加载。
   
2.1开启延迟加载
全局配置文件中配置

Java经典框架之MyBatis_第76张图片

  

Java经典框架之MyBatis_第77张图片

  
2.2 1对1延迟加载
要开启延迟加载那么我们的SQL语句查找操作也得分成多次操作。
    
        
        
        
        
            
            
        
    

    

    
  

Java经典框架之MyBatis_第78张图片

   
延迟加载的效果
只使用主表数据,没有使用从表数据的操作,会开启延迟加载。
  

Java经典框架之MyBatis_第79张图片

  
当使用了从表的数据那么就会操作从的数据。
  

Java经典框架之MyBatis_第80张图片

  
2.3 1对多的延迟加载
同样的也得将SQL语句拆分为多个SQL执行。
    
        
        
        
            
            
            
        
    

    
    
  

Java经典框架之MyBatis_第81张图片

  

Java经典框架之MyBatis_第82张图片

  
3. 缓存

缓存简介:
缓存(Cache )是计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝,应用程序在运行时直接读写缓存中的数据,只在某些特定时刻按照缓存中的数据来同步更新数据存储源。
缓存的物理介质通常是内存,而永久性数据存储源的物理介质通常是硬盘或磁盘,应用程序读写内在的速度显然比读写硬盘的速度快,如果缓存中存放的数据量非常大,也会用硬盘作为缓存的物理介质。缓存的实现不仅需要作为物理介质的硬件,同时还需要用于管理缓存的并发访问和过期等策略的软件。因此,缓存是通过软件和硬件共同实现的。
  
作用:降低访问数据源【数据库】频率。
  
3.1缓存分类

Java经典框架之MyBatis_第83张图片

  
MyBatis支持1级缓存和2级缓存,在实际开发中,实际上很少使用到MyBatis自带的缓存,大部分情况下,缓存都是使用EHCache,MemoryCache、Redis等等来实现缓存。
    
3.2 一级缓存
MyBatis中的一级缓存是基于SqlSession的。
@Test
public void fun1() throws Exception{
    InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    // 事务开启
    SqlSession sqlSession = factory.openSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    // 第一次查询员工信息 一级缓存中是没有数据的,所以会直接查询数据库中的数据
    // 然后会将数据保存到一级缓存中
    List emps = mapper.queryEmp();
    for (Emp emp : emps) {
        System.out.println(emp+" : " + emp.getDept());
    }
    System.out.println("----------------------");
    // 第二次查询 因为一级缓存中已经存在了要查询的数据,所以就直接返回了,没有数据库查询操作
    emps = mapper.queryEmp();
    for (Emp emp : emps) {
        System.out.println(emp+" : " + emp.getDept());
    }
    // 事务关闭 会清空一级缓存的数据
    sqlSession.close();
    // 重新开启事务
    sqlSession = factory.openSession();
    mapper = sqlSession.getMapper(EmpMapper.class);
    // 因为是新开的事务,一级缓存中的数据是空的,所以会直接查询数据库中的数据
    emps = mapper.queryEmp();
    for (Emp emp : emps) {
        System.out.println(emp+" : " + emp.getDept());
    }
    sqlSession.close();
}
    

Java经典框架之MyBatis_第84张图片

  
3.3 二级缓存
二级缓存是基于SqlSessionFactory的,一级缓存的作用域仅仅只是SqlSession,范围比较窄,应用不多,二级缓存是进程级别的,用的就比较多了。二级缓存我们一般使用Redis或者Ehcache来实现。

    net.sf.ehcache
    ehcache
    1.5.0



    org.mybatis.caches
    mybatis-ehcache
    1.1.0
  
开启二级缓存,我们只需要在需要开启的映射文件中添加cache标签即可。
@Test
public void fun1() throws Exception{
    InputStream in = Resources.getResourceAsStream("mybatis-cfg.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    // 事务开启
    SqlSession sqlSession = factory.openSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    // 第一次查询员工信息 一级二级缓存中是没有数据的,所以会直接查询数据库中的数据
    // 然后会将数据保存到一级缓存和二级缓存中
    List emps = mapper.queryEmp();
    for (Emp emp : emps) {
        System.out.println(emp+" : " + emp.getDept());
    }
    System.out.println("----------------------");
    // 第二次查询 因为一级缓存中已经存在了要查询的数据,所以就直接返回了,没有数据库查询操作
    emps = mapper.queryEmp();
    for (Emp emp : emps) {
        System.out.println(emp+" : " + emp.getDept());
    }
    // 事务关闭 会清空一级缓存的数据 但不会清空二级缓存的数据
    sqlSession.close();
    // 重新开启事务
    sqlSession = factory.openSession();
    mapper = sqlSession.getMapper(EmpMapper.class);
    // 因为是新开的事务,一级缓存中的数据是空的,但是二级缓存中有相关的数据 直接返回
    emps = mapper.queryEmp();
    for (Emp emp : emps) {
        System.out.println(emp+" : " + emp.getDept());
    }
    sqlSession.close();
}
  

Java经典框架之MyBatis_第85张图片

  

六、MyBatis的实际应用

1.MyBatis和Spring的整合操作
创建一个普通的Maven项目即可。
  
1.1 添加相关的依赖


    4.0.0

    com.bobo
    MyBatisDemo11Spring
    1.0-SNAPSHOT

    
        
        
            org.springframework
            spring-context
            5.1.6.RELEASE
        
        
            org.springframework
            spring-orm
            5.1.6.RELEASE
        
        
        
            org.mybatis
            mybatis
            3.4.6
        
        
            mysql
            mysql-connector-java
            8.0.11
        
        
            org.slf4j
            slf4j-log4j12
            1.7.25
        
        
        
            org.mybatis
            mybatis-spring
            2.0.4
        
        
        
            junit
            junit
            4.12
            test
        
        
        
            com.mchange
            c3p0
            0.9.5.2
        
    

    
        
            
                src/main/java
                
                    **/*.xml
                
                true
            
            
                src/main/resources
                
                    *.xml
                    *.properties
                
                true
            
        
    

  
1.2 创建相关的配置文件
MyBatis的全局配置文件



  
Spring的配置文件



    
    
    
    

    
    
        
        
        
        
    

    
    
        
        
        
        
        
        
    
    
    
        
    
  
db.properties文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/shop?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
username1=root
password=123456

#driver=com.mysql.cj.jdbc.Driver
#url=jdbc:mysql://192.168.100.122:3306/shop?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
#username=root
#password=123456
   
log4j.properties文件
log4j.rootCategory=All, stdout , R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n

log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=D:\\logs\\qc.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
    
1.3 业务测试
JavaBean对象
package com.bobo.pojo;

public class User {

    private Integer id;

    private String username;

    private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
    
Mapper接口和映射文件
package com.bobo.mapper;

import com.bobo.pojo.User;

import java.util.List;

public interface UserMapper {

    List query();
}




    
  
service
package com.bobo.service;

import com.bobo.pojo.User;

import java.util.List;

public interface IUserService {
    List query();
}
package com.bobo.service.impl;

import com.bobo.mapper.UserMapper;
import com.bobo.pojo.User;
import com.bobo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper mapper;

    @Override
    public List query() {
        return mapper.query();
    }
}
   
测试
@Test
public void test(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    IUserService bean = ac.getBean(IUserService.class);
    List list = bean.query();
    for (User user : list) {
        System.out.println(user);
    }
}
  

Java经典框架之MyBatis_第86张图片

  
整体的项目结构
  

Java经典框架之MyBatis_第87张图片

  
课后的作业:实现SpringMVC+Spring+MyBatis的整合。
  
2.逆向工程
2.1 什么是逆向工程
简单点说,就是通过数据库中的单表,自动生成Java代码。Mybatis官方提供了逆向工程,可以针对单表自动生成Mybatis代码(mapper.java\mapper.xml\po类)企业中,逆向工程是个很常用的工具,比我们手动创建映射文件的配置信息方便很多。
  
官网 http://www.mybatis.org/generator
    
2.2 逆向工程实现
添加mybatis-generator-maven-plugin插件

    
        
            org.mybatis.generator
            mybatis-generator-maven-plugin
            1.3.2
            
                true
                true
            
        
    
   
添加自动生成的配置文件
注意配置文件的名称必须是generatorConfig.xml




    
    

    
        
        
            
        
        
        
        

        

        
            
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
  
自动生成代码

Java经典框架之MyBatis_第88张图片

  

Java经典框架之MyBatis_第89张图片

  
2.3 接口方法说明
UserBeanMapper接口中的方法说明。

Java经典框架之MyBatis_第90张图片

    
关键代码
package com.bobo.service.impl;

import com.bobo.mapper.EmpMapper;
import com.bobo.pojo.Emp;
import com.bobo.pojo.EmpExample;
import com.bobo.service.IEmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class EmpServiceImpl implements IEmpService {

    @Autowired
    private EmpMapper mapper;

    @Override
    public Emp queryEmpById(int id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public List query(Emp emp) {
        EmpExample empExample = new EmpExample();
        // 绑定查询的条件
        EmpExample.Criteria criteria = empExample.createCriteria();
        if(!"".equals(emp.getName()) && emp.getName() != null){
            criteria.andNameLike("%"+emp.getName() +"%");
        }

        if(emp.getId() != null && emp.getId() > 0){
            criteria.andIdEqualTo(emp.getId());
        }
        if(emp.getAge()!= null &&emp.getAge() > 0){
            criteria.andAgeEqualTo(emp.getAge());
        }
        return mapper.selectByExample(empExample);
    }

    @Override
    public Integer insert(Emp emp) {
        return mapper.insertSelective(emp);
    }

    @Override
    public Integer updateById(Emp emp) {
        return mapper.updateByPrimaryKeySelective(emp);
    }

    @Override
    public Integer deleteById(Emp emp) {
        return mapper.deleteByPrimaryKey(emp.getId());
    }
}

你可能感兴趣的:(企业级必备应用框架,java,mybatis,开发语言)