Mybatis

一、Mybatis环境搭建

(一)操作

  • 引入依赖:
 
        
        org.mybatis
        mybatis
        3.5.13
    
    
        
        mysql
        mysql-connector-java
        8.0.32
    
  • mybatis配置文件(推荐命名:mybatis-config.xml)(放在resource中)



    

        
    
    
        
            
            
                
                
                
                
            
        
    
    

        
    
  • 注意配置文件因为标签是被约束的,所以二级标签的书写顺序有要求,从上到下顺序如下。

Mybatis_第1张图片

  • 创建mapper接口,并声明方法
@Mapper
public interface EmployeeMapper {

    //查询某个员工的信息
    Employee getEmployee(@Param("empId") int empId);


    //添加一个员工的信息
    int addEmployee(Employee employee);
}
  • 用到的实体类对象和对应表格结构
public class Employee {
     int eid;
     String empName;
     String empSex;
     int empAge;
     String empEmail;
     int did;

    public int getEid() {
        return eid;
    }

    public void setEid(int eid) {
        this.eid = eid;
    }

    @Override
    public String toString() {
        return "员工姓名" + empName + "员工性别" + empSex + "员工年龄" + empAge
                + "员工邮箱" + empEmail + "员工所在部门编号" + did;
    }
}

  • mapper接口对应的xml映射文件(一个mapper接口对应一个映射文件,在映射文件中以命名空间标识)(因为可能有多个映射文件所以放在mappers文件夹中)





    
  • 获得mapper的代理对象,并执行其中方法操作数据库
@Test
    public void testOne() throws IOException {
        //根据文件获取配置类的输入流
        InputStream rs = Resources.getResourceAsStream("mybatis-config.xml");
       //利用SqlSessionFactoryBuild建立SessionFactory
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(rs);
        //获取SqlSession对象
        SqlSession ss = sessionFactory.openSession();
        //根据接口类型来获取接口的动态代理对象执行声明的方法
        Employee rel=ss.getMapper(EmployeeMapper.class).getEmployee(3);
        //查看是否获取成功
        System.out.println(rel);
        //关闭流
        ss.close();
    }

(二)原理说明

A、mapper.xml文件和mapper接口的关系

  • 二者是一一对应关系,mapper的类的全路径对应xml文件中的命名空间,方法名对应xml文件中 select * from t_emp where eid = #{empId}

    C、测试代码:输出结果一致

    public class MyTest {
        @Test
        public void testOne() throws IOException {
            //根据文件获取配置类的输入流
            InputStream rs = Resources.getResourceAsStream("mybatis-config.xml");
           //利用SqlSessionFactoryBuild建立SessionFactory
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(rs);
            //获取SqlSession对象
            SqlSession ss = sessionFactory.openSession();
            //根据接口类型来获取接口的动态代理对象执行声明的方法
            Employee rel=ss.getMapper(EmployeeMapper.class).getEmployee(3);
            //查看是否获取成功
            System.out.println(rel);
            //关闭流,如果有dml操作,还要调用提交事务方法
            ss.close();
        }
        @Test
        public void testTwo() throws IOException {
            //....省略sqlsession对象获取过程,下面各测试方法一样省略
            //创建对象
            Employee testEmployee = new Employee();
            testEmployee.setEid(3);
            //根据接口类型来获取接口的动态代理对象执行声明的方法
            Employee rel=ss.getMapper(EmployeeMapper.class).getEmployeeByObjField(testEmployee);
            System.out.println(rel);
        }
           @Test
        public void testTwo() throws IOException {
            //创建对象
            Employee testEmployee = new Employee();
            testEmployee.setEid(3);
            HashMap myMap = new HashMap<>();
            myMap.put("one",testEmployee);
            //根据接口类型来获取接口的动态代理对象执行声明的方法
            Employee rel=ss.getMapper(EmployeeMapper.class).getEmployByMap(myMap);
            System.out.println(rel);
        }
         
        @Test
        public void testTwo() throws IOException {
            //创建对象
            Employee testEmployee = new Employee();
            testEmployee.setEid(3);
            ArrayList myList = new ArrayList<>();
            myList.add(testEmployee);
            //根据接口类型来获取接口的动态代理对象执行声明的方法
            Employee rel=ss.getMapper(EmployeeMapper.class).getEmployeeByList(myList);
            System.out.println(rel);
        }
    }

    (二)查询结果的返回

    A、返回类型的指定

    • java常用的基本类型直接在resultType中指定即可,但是自定义类型需要写全类名。
    • 当返回值时list集合时,我们在映射文件中只需要声明好其中泛型类型即可,返回结果即会自动填充list集合:

    mapper中声明的方法:

       //获得所有员工组成的集合:
        ArrayList getEmployees();

    xml中的映射部分:

    
        

    B、要想填写返回值时,自定义类也可以直接简写,可以在配置文件中加入别名配置

    • 单个类指定别名
    
    
            
        
    • 以包为单位指定,被指定别名的包中的类,别名都是类名首字母小写
    
        
            
        
    • 在以包为单位的前提下,单独给包下的类再起别名(这里pojo包已被指定别名)

    在想要单独设置别名的类加上如下注解

    @Alias("myEmployee")//这样该类的别名就成了myEmployee
    public class Employee {//...
    }
    //结构省略

    这样之后,就可以直接resultType中使用类的别名!

     C、返回集映射(可以自定义,表中列和对象属性的对应关系,关键是能够进行深层映射)

    • 深层映射就是指,当返回的对象中还有list和对象时,也能够指定他们中的属性值和表格具体列的映射(多级映射会在多表查询中用到)。
    • 之前我们因为在配置文件中开了驼峰命名规则的设置,再加上我们类命名时就是将数据库表中的xxx_xxx形式的字段变成了xxxXxx的命名,所以在映射时会默认将表格列名映射成对应驼峰从而注入。
    
    
            
        
    • 这里我们先关闭驼峰,在xml文件中自定义映射规则

    xml文件内容:

    
        
    
            
    
            
            
            
            
        
    
        

    只用在resultMap属性中指定自定义映射的id才会使用,没有就不使用,这里太局限,我们还开启驼峰映射配置。 

    D、属性自动提交可以在获取sqlSession时传入参数指定事务自动提交

    SqlSession ss = sessionFactory.openSession(true);

    这样就省去了最后的提交操作

    ss.commit();

    (三)数据添加后,返回关键字到对象的指定属性(主键回显)

    环境:

    mapper接口中方法:

    //添加一个员工的信息,并返回主键
        int addEmployee(Employee employee);

     A、情况一:当添加的数据行有自增长的关键字,在insert标签(其他dml标签亦可)加如下属性。

    xml文件中的内容:

    
        
            insert into t_emp(emp_name,emp_sex,emp_age,emp_email,did) values(#{empName},#{empSex},#{empAge},#{empEmail},#{did})
        

    这样数据添加后,主键就会返回到添加对象的eid属性上

    @Test
        public void testOne() throws IOException {
            //省略SqlSession对象回去过程。
            //创建要加入到数据库的对象
            Employee employee = new Employee("翩久遇","女",18,"[email protected]",2);
            //返回的值还是影响的行数,但是主键值会被添加到参数的对象指定属性中
            int keyRel=ss.getMapper(EmployeeMapper.class).addEmployee(employee);
            //查看对象相关属性看看是否成功
            System.out.println("新添加的员工的员工号是: " + employee.getEid());
            //添加操作是dml操作,需要ss.commit()操作提交事务
            ss.commit();
            ss.close();
        }

    B、当表中的关键字需要自定义生成时,声明方式发生变化

    • 我们选用新添加员工的email作为新添加关键字自定生成的字段(虽然有点不合理,但我使用的是uuid)

    xml文件内容:

    
         
            
               
               select  replace(uuid(),"-","")
            
            insert into t_emp(emp_name,emp_sex,emp_age,emp_email,did) values(#{empName},#{empSex},#{empAge},#{empEmail},#{did})
        

    测试,添加新对象,把email属性空出来,接收数据库创建的uuid值,即关键字。

          Employee employee = new Employee("翩久见","男",43,null,2);
            //返回的值还是影响的行数,但是主键值会被添加到参数的对象指定属性中
            int keyRel=ss.getMapper(EmployeeMapper.class).addEmployee(employee);
            //查看对象相关属性看看是否成功
            System.out.println("新添加的员工邮箱是: " + employee.getEmpEmail());
            //添加操作是dml操作,需要ss.commit()操作提交事务
            ss.commit();
            ss.close();

    三、多表查询

    环境准备:

    • 两个对象对应数据库两张表:
    public class Employee {
         int eid;
         String empName;
         String empSex;
         int empAge;
         String empEmail;
         int did;
         Department department;
       //省略其他gettersetter和构造器,重写toString的结构
    }
    
    
    public class Department {
        int did;
        String deptName;
    }

    Mybatis_第2张图片

    Mybatis_第3张图片

    (一)一对一关系查询

    A、分析:

    • 一对一关系是你中有我我中有你的关系,这里我们通过查询员工获得其对应部门的信息,所以我们需要在employee属性中加上Department对象(见上),来做接收准备:
    • 查询语句要用到多表查询语句,跟之前单表不同,应该再创建一个接口及映射文件来声明方法和sql语句。

    Mapper接口叫做:EmpAndDeptMapper 映射文件同名,然后在配置文件中加入映射文件。

     

    B、具体逻辑(重要:多层映射的声明)

    
    
    
    
    
        
          
           
            
            
            
    
            
                
                
            
        
    
      
    

    mapper接口内容:

    @Mapper
    public interface EmpAndDeptMapper {
        //获取部门及其对应部门的方法,多表查询,一对多
        Employee getEmployeeAndDept(@Param("eid")int eid);
    }

    C、一对多关系

    A、分析:

    • 一对多关系,要从一的一方获得多的一方,一的一方要包含多的一方,故Department类要有一个关于Employee的集合ArrayList
    • 那么在查询时Employee中的department对象还需要赋值吗(一对一关系查询的残留),需要,与该查询无关。

    B、具体执行

    • 首先在Department加入list属性
      List employees;
    • 在接口中声明方法
    //获得一个部门对应的多个员工信息
        Department getDepartmentAndEmp(@Param("did") int did);

    • xml文件内容:
    
        
            
            
    
            
                
                
                
                
                
            
        
    

    (三)开启配置简化自定义映射结构

    • 相关配置项官网截图

    • 开启配置项
    
            
    •  开启该配置项后,自动映射中设置的内容result的内容就可以省略不写,因为我们开启了驼峰命名映射,会自动进行映射。下面以一对多自定义映射内容简化展示(注释是相对于之前减少的):
    
        
            
    
    
            
                
    
    
    
    
            
        

    四、动态sql语句

    (一)什么是动态sql

    动态sql就是mybatis的一套标签,能够实现有条件地增加sql语句,代替之前自己的sql拼接操作。

    (二)动态sql用到的标签

    A、if标签的作用:

    • 那多表查询的sql语句为例,在sql语句后插入if标签,test属性判读条件,如果条件满足,if标签中的内容就会被拼接到sql语句中。
    • 多个if可以同时使用,只要满足判断条件的都会被拼接到sql语句中。

    这是候就存在两个特殊情况,导致sql语句错误

    1. 当两个if标签都不满足,那么where标签就多出来了
    2. 当第二个条件满足,第一个条件不满足,那么语句就会被拼接,如下where and ....这是错误的语法,当只有一个条件时不能加and。
    3. 解决这个问题就需要标签出场了

    B、where标签的作用

    • where标签会智慧地判断其中包含的if判断是否生效,如果没有一个生效,就不加where,如果有条件生效,会只能拼接去掉多余的结构,比如说上面的and。
    • 如下声明:

    注意当where标签因为没有条件满足时不添加,返回的就是两个对象,要用List承接。

    C、set标签作用

    • 方法传参:
    int updateEmployeeEmail(@Param("eid") int eid,@Param("empName") String empName,@Param("empAge") int empAge);
    • xml中内容:
    
        update t_emp
        
    
            
                emp_name = #{empName},
            
    
            
                emp_age = #{empAge}
            
        
        where eid= #{eid}
    

    这样就存在一种情况,当要修改年龄在10到20岁时的姓名时,后面多了个逗号

    别担心,因为在set标签总,它会自动判断,删除前后多余符号。

    D、trim标签的替代性

    • 上面的标签和标签都有以下特点
    1. 当标签内没有条件满足时,不仅不添加条件更不加where标签
    2. 当标签中的if标签有满足的情况,就加上where或set标签,并切会自动去除if标签中前后多余的符号
    • 根据以上两个特点我们可以使用trim标签作为通用标签,标签中有两个属性一个是prefix用来指定当没有条件满足时应该或有条件满足时应该增加或减少什么标签;suffixOverrides用来指定当有条件满足时,前面的什么文本应该被剪去,prefixOverrides用来指定当前面有什么多余文本会被替代。下面代码演示:
    
        update t_emp
       
    
            
                emp_name = #{empName},
            
    
            
                emp_age = #{empAge}
            
        
        where eid= #{eid}
    

    E、choose、when、otherwise组合使用,实现条件判断

    • 这三个标签可以实现多条件的单一满足实现,即是说,当条件有很多时,只要满足其中之一,下面的条件就不再校验是否满足,when中放条件判断及sql语句,otherwise中放最终兜底sql,
    • 下面例子实现了,当条件判断eid为5或6,或者年龄为18时才能修改名字,否则,名字和年龄都设成18和待定。
    
        update t_emp
    
       
           
               
                   emp_name = #{empName},
               
               
                   emp_name = #{empName},
               
               
                   emp_name = #{empName} ,
               
    
               
                   emp_age=18,emp_name="待定"  
               
           
       
        where eid = #{eid}
    

    F、foreach的使用

    • foreach能够智能地遍历传入的list集合
    • 何以见得,一般我们要根据eid批量插入数据都要用到in(),里面放入各种数据,这里就可以用循环标签做到。
    
           update t_emp set emp_age = emp_age + 1 where eid in
    
           
               #{eid}
           
           
       

    调用该方法给每位员工年龄加一:

    //先创建所有员工eid的集合
            Integer[] me = new Integer[]{1,2,3,4,5,6,11,12,13,14,17,18,19};
              List empsEids = Arrays.asList(me);
            //获取EmpAndDeptMapper的代理对象,并调用方法获取结果
          int  Rel = ss.getMapper(EmpAndDeptMapper.class).addEmployeeAgeOneByEid(empsEids);
            //查看对象相关属性看看是否成功
            System.out.println(Rel);
            ss.commit();
            ss.close();

    G、sql片段 

    • 就是将sql语句专门声明在一个地方,方便复用,我们将上面循环加年龄的sql提取出来作为例子。
    
        
            update t_emp set emp_age = emp_age + 1 where eid in
        
       
    
           
    
           
               #{eid}
           
           
       

    五、按包批量扫描xml映射文件

    (一)要求:

    • xml文件名和接口名保持一致
    • resource下的xml文件的文件夹结构和接口所在的包的层级结构一致(这样在打包后的映射文件和接口就在一块,打包后包就是文件夹)

    Mybatis_第4张图片

    (二)声明方式:

    配置文件中:

    
    
    
    
            
        

    六、分页插件(pagehelper)的使用

    (一)分页插件的原理概析

    该插件就是在你的查询语句之后加上limit x,y这一原生的查询限制,实现分页效果

    • x指开始的坐标,y指偏移量
    • 要想利用x 和y 实现分页我们应该这样书写 limit  (页码-1)*每页条数   每页条数;
    • 该插件实现了我们不需要关注上面的式子,我们只需要告诉其是第几页,每页有多少条数据即可。

    (二)使用

    • 首先引入插件:
    
    
            com.github.pagehelper
            pagehelper
            5.2.0
        
    • 然后在mybatis配置文件中声明引入的插件和插件对应的数据库(不同数据库分页指令不一样)
     
                                   
               
                             
                                                                  
                                                                 
    • 最后就是使用了
    @Test
        public void testOne() throws IOException {
            //.................
           //前面省略SqlSession对象ss的获取过程
            //通过插件提供的方法设置要页码和每页的数据条数
            PageHelper.startPage(2,4);
          List  rel = ss.getMapper(EmployeeMapper.class).getEmployees(2);
          //然后我们将查询到的结果放入PageInfo对象中
            PageInfo pageInfo = new PageInfo<>(rel);
            //然后我们就可以根据该对象获取有关分页的各种数据,包括一共几页,每页多少数据等信息,
            //还可以将数据list集合在获取出来
            List list = pageInfo.getList();
            System.out.println(list);
            //获取一共几页:
            System.out.println("一共:" +pageInfo.getPages() + "页");
            //查看对象相关属性看看是否成功
            ss.commit();
            ss.close();
        }
    • 分页后每页的结果就是一个集合集合中有这页的相关信息:
    Page{count=true, pageNum=2, pageSize=4, startRow=4, endRow=8, total=13, pages=4, reasonable=false, pageSizeZero=false}[Employee{eid=5, empName='梅长波', empSex='男', empAge=21, empEmail='[email protected]', department=null}, Employee{eid=6, empName='暴冲飞', empSex='女', empAge=21, empEmail='[email protected]', department=null}, Employee{eid=11, empName='暴冲驰', empSex='女', empAge=25, empEmail='[email protected]', department=null}, Employee{eid=12, empName='暴冲飞', empSex='女', empAge=25, empEmail='[email protected]', department=null}]

    七、逆向工程与MyBatisX插件的使用

    (一)orm思想的实现

    • 所谓orm(object-Relational Mapping)对象关系映射就是说,本来我们通过Jdbctemplate来操作数据库需要自己写sql语句,抹杀了java的面向对象性,orm指直接面向对象操作数据库,我们不用自己写sql语句,通过插件自动生辰。
    • 依上可知,我们的mybatis是半自动orm实现,因为我们还是要写sql,但通过代理实现了面向对象。
    • 逆向工程就是全自动orm它自动生成数据库单表和实体类的映射,自动创建相关增删改查方法的接口,以及映射文件实现。

    (二)MyBatisX插件的使用

    • 首先搜索并下载插件
    • 通过database选项连接数据库。

    Mybatis_第5张图片

    • 然后打开一个,使用插件构建

    Mybatis_第6张图片

    • 构建过程如下:

    Mybatis_第7张图片

    next

    Mybatis_第8张图片

    完成后,工程中相应位置就会出现实体类,xml文件和mapper接口

    Mybatis_第9张图片

    里面提供了基本的单表增删改查操作:

    public interface TUserMapper {
    
        int deleteByPrimaryKey(Long id);
    
        int insert(TUser record);
    
        int insertSelective(TUser record);
    
        TUser selectByPrimaryKey(Long id);
    
        int updateByPrimaryKeySelective(TUser record);
    
        int updateByPrimaryKey(TUser record);
    
    }

     映射文件中也自动写好了sql语句,可以直接使用,实现了orm思想

你可能感兴趣的:(mybatis)