栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

万字大章学习MyBatis

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

万字大章学习MyBatis

文章目录

MyBatis

搭建核心配置文件

数据库环境配置属性设置设置setting类型别名其它配置项 逆向工程

创建逆向工程使用逆向工程 动态SQLMyBatis查询

一对一关联查询一对多关联查询多对多关联查询分页查询

方案一:使用Page工具类方案二:使用RowBounds插件 延迟加载(Lazy Load)

延迟加载配置实现延迟加载 MyBatis查询缓存

一级缓存二级缓存二级缓存补充

MyBatis

基于Java的数据持久层(ORM)框架。把实体类和SQL语句之间建立了映射关系,是一种半自动化的ORM实现。

(1)ORM对象关系映射,一种数据持久化技术。
		O:Object	对象===java中的实体类---对象
		R:Relation	关系===关系型数据库---表
		M:Mapping	映射===提供一种映射的机制
		
(2)半自动化:在映射过程中需要写一些SQL语句才能完成指定功能
搭建

    创建Maven工程。

    添加项目依赖。



    org.mybatis
    mybatis
    3.5.6


    mysql
    mysql-connector-java
    8.0.16


    junit
    junit
    4.12
    test


	log4j
	log4j
	1.2.17

    创建MyBatis全局配置文件。



  
    
        
          
            
          
            
                
                
                
                
            
        
    
  
    
        
    

    创建实体类。

    创建sql映射文件。




    
        select *
        from Blog
        where id = #{id}
  

    测试。
核心配置文件

核心配置文件下载地址


核心配置文件sqlMapperConfig中的标签顺序应按照上面的顺序:properties—>mappers

数据库环境配置
    
        
          
            
          
            
                
                
                
                
            
        
    
属性设置

1.在属性中配置对应的数据。

 
    
        
    
    

    
        
          
            
          
            
                
                
                
                
            
        
    

2.提取属性到一个全新的文件(jdbc.properties)进行引用

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssm_db
username=root
password=rootstart

    
    
      
    
  
  
    
        
          
            
          
            
                
                
                
                
            
        
    


3.赋默认值(以password为例)


    
    
    		
        
    


  
    
        
          
            
          
            
                
                
                
                
            
        
    

设置setting
    
        
        
        
        
        
        
    
类型别名

1.标签设置,依次设置


     

2.直接设置一个包


		

其它配置项
    类型处理器 typeHandlers对象工厂 objectFactory插件 plugins映射器 mappers

		

逆向工程

​ Mybatis需要自己编写SQL,若是表太多的话难免会麻烦,所以官方提供了一种逆向工程,可以针对单个表自动生成Mybatis执行所需要的代码(包括Mapper.xml、mapper.java、pojo)。一搬我们在开发中常用的逆向工程是通过数据库的表生成代码。

创建逆向工程
    新建一个maven工程。添加依赖的jar包。

  mysql
  mysql-connector-java
  8.0.16




  log4j
  log4j
  1.2.17





    org.mybatis.generator
    mybatis-generator-core
    1.3.7


    添加配置文件generatorConfig.xml文件,用于设置数据库驱动,配置,包名,文件保存位置,表名等等。定义GeneratorSqlmap类,调用MyBatis自动创建接口,在main方法执行自动创建。

使用为主!!!

使用逆向工程
    添加generatorConfig.xml文件




    
        
            
            
        

        
        
        

        
        
            
        

        
        
            
            
            
            
        

        
        
            
            
        

        
        
            
            
        

        
        
        
    运行逆向工程的服务程序
public class GeneratorSqlmap {
    public void generator() throws Exception {
        List warnings = new ArrayList<>();
        boolean overwrite = true;

        //加载核心配置文件
        File configFile = new File("/Users/caiweidong/IdeaProjects/myCode/mybatisDemo/src/main/resources/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);
    }

    //程序入口^o^
    public static void main(String[] args) throws Exception {
        GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
        generatorSqlmap.generator();
    }
}

动态SQL

​ 动态SQL可以解决JDBC或其它类似框架根据不同条件拼接SQL语句时需要注意各种规则的问题,例如拼接时需要注意空格、去掉列表最后一个列名逗号等等这些问题。

​ MyBatis提供了各种标签对条件作出判断可以实现动态拼接SQL语句。

    if标签(实现查询)

​ if进行判断,test的内容是表达式,使用like进行模糊查询,%作为占位符, 进 行 拼 接 查 询 , c o n c a t ( ) 表 示 字 符 串 拼 接 , {}进行拼接查询,concat()表示字符串拼接, 进行拼接查询,concat()表示字符串拼接,{}无法被识别为字符串,因此要加单引号,#{}可以被识别为字符串,无需加单引号。由于在mapper文件中<会被识别成一个标签的开始,因此我们的< <= 是没有办法直接写的,因此需要转译:

select * from t_role where id > #{id}
	
      and name like "%${name}%"
  
  
select * from t_role where id>#{id}
  
      and name like concat('%','${name}','%')
  
  
select * from t_role where id#{id}
  
      and name like concat('%',#{name},'%')
  
    if-where标签(实现查询)

​ 当我们无法判断是否有条件时,使用where标签框架会自动判断我们是否需要where,如果所有条件都不满足就会查询出所有的记录,并且可以自动消除第一个and和or。

select * from t_role
 
     
         and id#{id}
     
     
         and name like concat('%',#{name},'%')
     
 
    choose-when-otherwise标签(实现查询)

​ 当我们不想使用所有的条件,只是想从多个条件中选择一个使用时,我们可以选择choose标签,类似于switch语句。choose标签可以按照顺序判断when标签中的条件是否成立,有一个成立时choose就会结束。当when的所有条件都不满足时,会执行otherwise中的语句。类比switch语句,chooseswitch,whencase,otherwise==default。

select * from t_role where

    
        id#{id}
    
    
        and name like concat('%',#{name},'%')
    
    
        userid = #{userid}
    

    trim-if标签(实现添加)

​ trim标签可以在在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix。或将包含内容的首部(或尾部)某些内容覆盖,对应的属性是prefixOverrides和suffixOverrides。

insert into t_role

    
        name,
    
    
        userid,
    
    
        oper_time,
    

values

    
        #{name},
    
    
        #{userid},
    
    
        #{operTime},
    

    set-if-where标签(实现修改)

set标签用在修改的操作,作用和where差不多,使用set标签可以在包含的语句前面输出一个set,若包含的语句以逗号结尾会将逗号省略


    
    update t_role
    
        
            name = #{name},
        
        
            userid = #{userid},
        
        
            oper_time = #{operTime},
        
    
    
        
            and id = #{id}
        
        
            and id = -1
        
    

    foreach标签-构建in条件

    foreach标签用于构建in条件,在SQL语句中进行迭代一个集合。

    foreach标签的属性主要有:

属性作用
item表示迭代集合中每一个元素的别名。
index指定一个名字表示在迭代过程中每次迭代到的位置。
open表示语句以什么开始。
separator表示每次迭代以什么符号作为分割符。
close表示语句以什么为结束。
collection单参且参数类型为List,属性为list;单参且类型为数组,属性为array;多参为Map。

实际如果在传入参数的时候,在MyBatis里面也会把他封装成一个Map的,Map的key就是参数名,所以在这个时候collection属性值就是传入的List或Array对象在自己封装的Map里面的Key。



    select * from t_role where id in
        
            #{roleId}
        




    select * from t_role where id in
    
        #{roleId}
    


    SQL片段(重复利用相同的SQL片段)

    select * from t_role



     
     where id in
        
            #{roleId}
        



    bind标签

    允许在OGNL表达式外创建一个变量,并将其绑定在当前的上下文。



 	sql语句

一对多关联查询

​ 使用resultMap。

public class User {
    private Integer id;

    private String account;

    private String password;

    private Integer type;

    private String fileName;

    private List roles;
}


public class Role {
    private Integer id;

    private String name;

    private Integer userid;

    private Date operTime;
}

    
    
    
    
    
  
    
        
        
        
        
    



    SELECT
        u.uid,
        u.uname,
        u.sex,
        u.birthday,
        u.address,
        o.oid,
        o.orderid,
        o.createtime,
        o.STATUS,
        od.odid,
        od.itemnum,
        i.iid,
        i.NAME,
        i.detail,
        i.price
    FROM
        users AS u
            INNER JOIN orders AS o ON u.uid = o.userid
            INNER JOIN orderdetail AS od ON o.orderid = od.orderid
            INNER JOIN items AS i ON od.itemid = i.iid
    WHERe
        u.uid = #{uid}

分页查询 方案一:使用Page工具类
    创建util工具类page
public class Page {
    //获得表里一共有多少条数据
    private Integer dataCount;

    //每页显示多少条数据
    private Integer showData;

    //一共分成多少页
    private Integer pageCount;

    //当前是第几页
    private Integer pageIndex;

    //当前页面显示的集合信息
    private List list;

    public Integer getDataCount() {
        return dataCount;
    }

    public void setDataCount(Integer dataCount) {
        this.dataCount = dataCount;
    }

    public Integer getShowData() {
        return showData;
    }

    public void setShowData(Integer showData) {
        this.showData = showData;
    }

    public Integer getPageCount() {
        //数据库的总条数如果能除尽每页显示的条数就直接赋值,若不能则除数取整+1
        return this.pageCount = this.dataCount%this.showData==0 ? this.dataCount/this.showData:this.dataCount/this.showData+1;
    }

    public Integer getPageIndex() {
        return pageIndex;
    }

    public void setPageIndex(Integer pageIndex) {
        this.pageIndex = pageIndex;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }
}
    创建接口方法,获取数据库总条数和第x列的数据集合
//分页获得一共有多少条数据
int selectCount() throws Exception;

//获得当前页显示的集合信息
List selectUsersByPage(Page page) throws Exception;
    创建两个方法对应的xml文件

    
    select * from users order by uid limit #{beginIndex},#{showData}

    调用方法进行使用
public class test {

    private SqlSessionFactory factory;

    @Before
    public void init() throws IOException {
        InputStream res = Resources.getResourceAsStream("sqlMapperConfig.xml");
        SqlSessionFactoryBuilder fac = new SqlSessionFactoryBuilder();
        factory = fac.build(res);
    }

    @Test
    public  void test2() throws Exception {
        SqlSession sqlSession = factory.openSession();
        UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
        Page page = new Page<>();
        //一共有多少条数据
        int dataCount = mapper.selectCount();
        System.out.println(dataCount);
        page.setDataCount(dataCount);
        page.setShowData(2);
        page.setPageIndex(1);
        //获取对应页的数据集合
        List users = mapper.selectUsersByPage(page);
        System.out.println(users);
        page.setList(users);
        sqlSession.close();
        for (Users user : page.getList()) {
            System.out.println(users);
        }
    }
}
方案二:使用RowBounds插件
    创建实体类.创建接口,参数使用RowBounds
//RowBounds插件,分页插件
List selectItems(RowBounds rb) throws Exception;
    创建对应的xml文件

    select * from orderdetail where odid = #{odid}





    测试代码
@Test
public  void test4() throws Exception {
    SqlSession sqlSession = factory.openSession();
    OrderDetailMapper orderDetailMapper = sqlSession.getMapper(OrderDetailMapper.class);
    ItemsMapper itemsMapper = sqlSession.getMapper(ItemsMapper.class);
    OrderDetail orderDetail = orderDetailMapper.selectOrserDatailLazyLoad(2);
    sqlSession.close();
    System.out.println(orderDetail.getOrderid());
    System.out.println(orderDetail.getItems());
}
MyBatis查询缓存

​ 缓存是用“空间换时间”的设计理念,利用内存空间的资源来提高检索速度的手段之一。MyBatis包含一个非常强大的查询缓存特性,可以方便的进行配置和定制,它提供了一级缓存和二级缓存。一级缓存基于PerpetualCache的HashMap本地缓存,存储的作用域是Session,当Session被flush或close后,该Session中的所有Cache就将被清空;

二级缓存与一级缓存的机制类似,默认使用PerpetualCahce(长期缓存),hashMap存储,但它的作用域为Mapper,可以自定义存储源(Ehcache、hazelcast等)。

一级缓存

​ MyBatis默认开启一级缓存,不需要进行配置,同一个SqlSession对象中,第二次进行相同的查询时,直接获取到缓存数据,不需要去执行sql再到数据库中纪念性查询。

同一个session:
获得session对象(开始)
--->
session.commit() 或 session.close() 或 session.flush()
--->
结束
二级缓存

​ MyBatis的二级缓存是Mapper范围级别,需要在MyBatis的全局配置文件中设置二级缓存的开关,还需要在具体的mapper.xml中开启二级缓存。

    添加二级缓存的相关jar包依赖

    org.mybatis.caches
    mybatis-ehcache
    1.0.2




    net.sf.ehcache
    ehcache
    2.10.1

    在Mybatis全局配置文件中手动开启配置文件

    
    

    在各自的sql映射文件中单独开启二级缓存

    实体类进行序列化
public class Items  implements Serializable {

5.测试

@Test
public  void test5() throws Exception {
    SqlSession sqlSession = factory.openSession();
    ItemsMapper itemsMapper = sqlSession.getMapper(ItemsMapper.class);
    Items items = itemsMapper.selectItemsById(1);
    System.out.println("第一个SqlSession的商品信息:"+items);
    sqlSession.close();

    SqlSession sqlSession1 = factory.openSession();
    ItemsMapper itemsMapper1 = sqlSession1.getMapper(ItemsMapper.class);
    Items items1 = itemsMapper1.selectItemsById(1);
    System.out.println("第二个SqlSession的商品信息:"+items1);
    sqlSession1.close();

}
二级缓存补充

    禁用二级缓存

    可以在sql语句所在标签使用属性useCache = “false” 用来禁用二级缓存