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

Mybatis学习

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

Mybatis学习

目录
  • 1. 简介
    • 1.1 什么是Mybatis?
    • 1.2 如何获得Mybatis?
  • 2. 创建第一个Mybatis程序
    • 2.1 搭建环境
    • 2.2 创建一个模块
    • 2.3 编写代码
    • 2.4 测试
    • 2.5 注意点
  • 3. CRUD
    • 3.1 namespace
    • 3.2 select
    • 3.3 insert
    • 3.4 update
    • 3.5 delete
    • 3.6 万能的Map
      • 总结
    • 3.7 模糊查询
  • 4. 配置分析
    • 4.1 核心配置文件
    • 4.2 环境配置(environments)
    • 4.3 属性(properties)
    • 4.4 类型别名(typeAliases)
    • 4.5 映射器(mappers)
  • 5. 生命周期
  • 6. 结果集映射(resultMap)
  • 7. 日志
    • 7.1 标准的日志工厂实现(STDOUT_LOGGING)
    • 7.2 Log4j
  • 8. 分页
  • 9. 注解
    • 9.1 注解开发
    • 9.2 注解实现CRUD
  • 10. Lombok
  • 11. 多对一
    • 11.1 测试环境搭建
    • 11.2 多对一的处理
  • 12. 一对多
  • 13. 动态SQL
    • 13.1 if
    • 13.2 where
    • 13.3 choose、when、otherwise
    • 13.4 set
    • 13.5 SQL片段
    • 13.5 foreach
  • 14. 缓存
    • 14.1 简介
    • 14.2 Mybatis缓存
      • 一级缓存
      • 二级缓存
    • 14.3 缓存原理

1. 简介 1.1 什么是Mybatis?

Mybatis是一款优秀的持久层框架
它支持定制化SQL、存储过程以及高级映射
Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
Mybatis可以使用简单的XML或注解来配置和映射原生类型、接口和Java的pojo为数据库中的记录

1.2 如何获得Mybatis?

maven仓库


    org.mybatis
    mybatis
    3.5.2

Github: https://github.com/mybatis/mybatis-3/releases
MyBatis文档网址:https://mybatis.org/mybatis-3/zh/index.html

2. 创建第一个Mybatis程序 2.1 搭建环境

1.新建一个普通的maven项目
2.删除src目录
3.加入maven依赖

    
    
        
            mysql
            mysql-connector-java
            5.1.47
        
        
            org.mybatis
            mybatis
            3.5.2
        
        
            junit
            junit
            4.12
        
    
2.2 创建一个模块

1.编写mybatis的核心配置文件





    
        
            
            
                
                
                
                
            
        
    

    
    
        
    

2.编写mybatis工具类

// SqlSessionFactory -->sqlSession
public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            // 使用Mybatis第一步:
            // 获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 使用Mybatis第二步:
    // 从 SqlSessionFactory 中获取 SqlSession
    // 既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    // 你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

2.3 编写代码

1.编写实体类(一个实体类对应一个表)并实现Serializable接口。

package com.liu.pojo;

//实体类
public class User implements Serializable{
    public int id;
    public String name;
    public String pwd;

    public User() {
    }
    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public String getPwd() {
        return pwd;
    }
    public void setId(int id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", pwd='" + pwd + ''' +
                '}';
    }
}

2.编写Dao接口

public interface UserDao {
    List getUserList();
}

3.编写接口对应的Mapper.xml文件(以前是一个UserDaoImpl对应一个UserDao,现在是一个Mapper.xml文件对应一个UserDao)






    
    
        select * from mybatis.user
    

测试

    @Test
    public void getUserById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User user=mapper.getUserById(1);
        System.out.println(user);

        sqlSession.close();
    }
3.3 insert

编写接口

    //插入
    int addUser(User user);

编写对应的mapper中的sql语句

	
    
        insert into mybatis.user(id, name, pwd) values (#{id},#{name},#{pwd})
    

测试

    //增删改查需要提交事务
    @Test
    public void addUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        int res = mapper.addUser(new User(4,"哈哈","123333"));
        if(res>0)
            System.out.println("插入成功!");

        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }
3.4 update

编写接口

    //修改
    int updateUser(User user);

编写对应的mapper中的sql语句

    
        update mybatis.user set name = #{name}, pwd = #{pwd} where id = #{id}
    

测试

    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        int res=mapper.updateUser(new User(4,"呵呵","111111"));
        if(res>0)
            System.out.println("修改成功!");

        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }
3.5 delete

编写接口

    //删除
    int deleteUser(int id);

编写对应的mapper中的sql语句

    
        delete from mybatis.user where id = #{id}
    

测试

    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        int res=mapper.deleteUser(4);
        if(res>0)
            System.out.println("删除成功");

        // 提交事务
        sqlSession.commit();
        sqlSession.close();
    }

注意点:增删改需要提交事务!!
另一种方式:不需要commit!
将openSession中的参数设为true即可。

3.6 万能的Map

假设我们的实体类,或者数据库中的表,字段或者参数过多,则应当考虑使用map。与直接传递对象的区别就在于使用map不一定要获取到所有的属性,而当使用User时,必须将所有的属性包揽在内

1.接口中参数声明为Map形式

    //修改:万能的Map
    int updateUser2(Map map);

2.Mapper中:参数类型是小写的map, 里面的值是map的key

    
    
        update mybatis.user set name= #{name} where id=#{id}
    

3.测试代码

    @Test
    public void updateUser2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        Map map=new HashMap();
        map.put("id",1);
        map.put("name","刘梦豪"); // 最大的区别就在于使用map不需要获取到所有的属性,而当使用User时,必须将所有的属性包揽在内

        mapper.updateUser2(map);
        sqlSession.commit();
        sqlSession.close();
    }
总结

Map传递参数,直接在sql中取出key即可!【parameterType=“map”】
#{key} 即可取到
对象传递参数,直接在sql中取对象的属性即可!【parameterType=“Object”】
#{对象包含的属性名}即可取到

对于方法中只有一个基本类型参数的情况下,可以直接在sql中取到!
#{参数名}
对于方法中多个参数:用Map,或者注解@Param("") 后续会讲到

3.7 模糊查询

1.编写接口

    // 模糊查询
    List getUserLike(String value);

2.编写对应的mapper中的sql语句并测试
方式一:

    
        select * from mybatis.user where name like "%"#{value}"%"
    

对应的测试代码为:

    @Test
    public void getUserLike(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        List userList = mapper.getUserLike("李");

        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
4. 配置分析 4.1 核心配置文件

一般命名为:mybatis-config.xml

configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
4.2 环境配置(environments)

MyBatis 可配置成适应多种环境
但是尽管可以配置多种环境,但每个 SqlSessionFactory 实例只能选择一种环境!

4.3 属性(properties)

我们可以通过properties来实现引用配置文件,这些属性都是可以外部配置且可动态替换的。既可以在典型的Java属性文件中配置,也可以通过properties元素的子元素来传递(db.properties)

编写一个配置文件

在核心配置文件中可引入外部配置文件

如果里面和外面的配置冲突了,优先使用外面的配置

4.4 类型别名(typeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
第一种写法:

    
    
        
        ...
    

第二种写法:扫描一个包,每个实体类的默认别名就为这个类的类名,首字母一般小写!(大写也行)

    
    
        
    

第三种写法:注解方式(在第二种写法的基础上,如果要修改名时则使用,如果一三写法同时使用,第一种生效)
直接在类的上面使用注解@Alias(“自定义名称”)

@Alias("hello")
public class User {
    ...
}
4.5 映射器(mappers)

每一个mapper都需要注册,注册mapper有三种方式
方式一:使用相对于类路径的资源引用


	
	 	
	 	...
	

方式二:使用映射器接口实现类的完全限定类名


  
  ...

方式三:使用扫描包进行注入


  
  ...

后两种方式的注意点:

  • 接口和他的Mapper配置文件必须同名!
  • 接口和他的Mapper配置文件必须在同一个包下!
5. 生命周期


SqlSessionFactoryBuilder:

  • 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

SqlSessionFactory:

  • 说白了就是可以想象为:数据库连接池
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  • 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次创建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。
  • 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession:

  • 是连接到连接池的一个请求
  • 每个线程都应该有它自己的 SqlSession 实例。
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 用完之后需要赶紧关闭,否则资源被占用!

    这里面的每一个Mapper,就代表一个具体的业务!
6. 结果集映射(resultMap)

当表的字段名与实体类字段名不对应的时候,要进行映射。(在mapper.xml文件中)
实体类对应属性名property,数据库字段名column

    
    
        
        
        
        
        
    

sql语句中的resultType改为resultMap

    
        select * from teacher where id = #{tid}
    

方式二:联表查询(按结果嵌套查询)
直接根据sql语句得到结果,然后去嵌套映射结果

    
    
        select s.id sid, s.name sname, t.name tname,t.id tid
        from student s,teacher t
        where s.tid = t.id and t.id = #{tid}
    

    
        
        
        
        
            
            
            
        
    

方式二:采用子查询的方式

    
    
        select * from mybatis.student where tid = #{tid}
    

测试代码

    @Test
    public void getTeacher(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //方式一:getMapper
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);

        //关闭SqlSession
        sqlSession.close();
    }

    @Test
    public void getTeacher2(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //方式一:getMapper
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher2(1);
        System.out.println(teacher);

        //关闭SqlSession
        sqlSession.close();
    }

小结:
1.关联- association【多对一】
2.集合- collection 【一对多】
3. javaType & ofType
 1. JavaType 用来指定实体类中属性的类型.
 2. ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类 型!
按照结果嵌套查询: 直接写出完整的连接查询sql语句,获取到想要的结果。然后再与实体类中的属性一一映射起来
按照子查询的方式: 先写出查询一个表的sql语句,然后在where条件中再去查询另一个表(即子查询)

13. 动态SQL

什么是动态SQL:

  • 动态SQL就是根据不同的条件生成不同的SQL语句。
  • 本质还是sql语句,只是我们可以在sql层面,去执行一个逻辑代码。
  • 动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了。
13.1 if

使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如:

    
        select * from mybatis.user
        
            
                id = #{id}
            
            
                and name =#{name}
            
        
    
13.3 choose、when、otherwise

类似于switch语句,若前面when满足,就不会再往后判断,当when中全不满足,则默认选otherwise

    
        select * from mybatis.user
        
            
        
    

测试代码

    @Test
    public void getUser()
    {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUser(1,"刘刘");
        System.out.println(user);
        sqlSession.close();
    }

注意:

  • 最好基于单表来定义SQL片段
  • 不要存在where标签
13.5 foreach

适用于对于一个属性有多个取值的sql语句
举例:比如查询id为1 2 3 的用户(用or)
select * from user where (id=1 or id=2 or id=3)

    
        select * from mybatis.user
        
            
                id = #{id}
            
        
    

提示: 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为collection参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。open是初始拼接字符串,close是末尾拼接字符串。separator是遍历对象间的分隔符

测试代码

    @Test
    public void getUser3()
    {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        HashMap map = new HashMap();
        ArrayList ids = new ArrayList();
        ids.add(1);
        ids.add(2);
        ids.add(3);
        map.put("ids",ids); // 将ids列表作为参数
        List userList= mapper.getUser3(map);
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
14. 缓存 14.1 简介

1.什么是缓存?

  • 存在内存中的临时数据
  • 将用户经常查询的数据放在缓存中,用户去查询数据就不用从磁盘上查询,从缓存中查询,从而提高查询效率,解决高并发系统的性能问题

2.为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率

3.什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据
14.2 Mybatis缓存

Mybatis 使用到了两种缓存:本地缓存(local cache)(一级缓存)和二级缓存(second level cache)。

一级缓存

一级缓存也叫本地缓存:SqlSession

  • 与数据库同一次会话期间查询到的数据会放在本地缓存中
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

测试步骤:

  • 开启日志!
  • 测试在一个Session中查询两次相同记录
  • 查看日志输出

测试代码

    @Test
    public void getUser()
    {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUser(1,"刘刘");
        System.out.println(user);
        System.out.println("======================================");
        user = mapper.getUser(1,"刘刘");
        System.out.println(user);
        sqlSession.close();
    }

如下图所示,缓存开启,查询两次相同的东西,只执行一次sql

缓存失效的情况:

  • 查询不同的东西
  • 增删改操作,可能会改变原来的数据,所以必定会刷新缓存
  • 查询不同的Mapper.xml
  • 手动清理缓存 sqlSession.clearCache();

一级缓存是默认开启的,只在一次SqlSession中有效!

二级缓存
  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存

  • 工作机制:

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话提交或关闭的时候,一级缓存中的数据被保存到二级缓存中;
    • 新的会话查询信息,就可以从二级缓存中获取内容;
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中;(也就是说只要开启了二级缓存,在同一个Mapper下就有效)

步骤:
1.开启全局缓存(mybatis-config.xml中setting里)

        
        

2.在SQL映射文件(xxxmapper.xml)中添加一行

	    
    	

也可以指定的详细一些:

   

总结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中
  • 只有当会话提交,或者关闭的时候,才会提交到二级缓存中
14.3 缓存原理

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/458407.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号