• Mybatis笔记(一)


    目录

    MyBatis

    MyBatis简介

    MyBatis作用

    • MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
    • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
    • MyBatis可以使用简单的XML用于配置和原始映射,将接口和Java的POJO类映射成数据库中的记录
    • 使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

    历史

    • 原是apache的一个开源项目iBatis
    • 2010年6月这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。
    • iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。

    为什么要使用MyBatis?

    JDBC

    • SQL夹在Java代码块里,耦合度高导致硬编码内伤
    • 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见
    • 要自已创建connection、创建statement、手动设置参数、结果集检索等

    Hibernate

    • 长难复杂SQL,对于Hibernate而言处理也不容易
    • 内部自动生产的SQL,不容易做特殊优化。
    • 基于全映射的全自动框架,javaBean存在大量字段时无法只映射部分字段。导致数据库性能下降。

    Mybatis

    • 对开发人员而言,核心sql还是需要自己优化
    • MyBatis是一个半自动化的持久化层框架。
    • MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。

    MyBatis入门程序

    1.下载Mybatis核心包

    http://www.mybatis.org/mybatis-3/getting-started.html
    https://github.com/mybatis/mybatis-3/releases

    2.创建工程,引入MyBatis核心包及依赖包

    ant-1.9.6.jar
    ant-launcher-1.9.6.jar
    asm-5.2.jar
    cglib-3.2.5.jar
    commons-logging-1.2.jar
    javassist-3.22.0-GA.jar
    junit-4.9.jar
    log4j-1.2.17.jar
    log4j-api-2.3.jar
    log4j-core-2.3.jar
    lombok.jar
    mybatis-3.4.6.jar
    mysql-connector-java-5.1.7-bin.jar
    ognl-3.1.16.jar
    slf4j-api-1.7.25.jar
    slf4j-log4j12-1.7.25.jar
    

    3.创建customer表,建立与表对象的domain

    package com.le.domain;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    @Setter@Getter@ToString
    public class Customer {
        private Integer cust_id;
        private String cust_name;
        private String cust_profession;
        private String cust_phone;
        private String email;
    }
    

    4.创建MyBatis核心配置文件SqlMappingConfig.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <!-- spring整合后 environments配置将废除 使用spring中的连接池 -->
        <environments default="development">
            <environment id="development">
                <!-- 使用jdbc事务管理 -->
                <transactionManager type="JDBC" />
                <!-- 数据库连接池 -->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver" />
                    <property name="url"
                              value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
                    <property name="username" value="root" />
                    <property name="password" value="1234" />
                </dataSource>
            </environment>
        </environments>
    </configuration>
    
    	<!DOCTYPE configuration
    			PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    			"http://mybatis.org/dtd/mybatis-3-config.dtd">
    	<configuration>
    		<!-- spring整合后 environments配置将废除 使用spring中的连接池 -->
    		<environments default="development">
    			<environment id="development">
    				<!-- 使用jdbc事务管理 -->
    				<transactionManager type="JDBC" />
    				<!-- 数据库连接池 -->
    				<dataSource type="POOLED">
    					<property name="driver" value="com.mysql.jdbc.Driver" />
    					<property name="url"
    							  value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
    					<property name="username" value="root" />
    					<property name="password" value="1234" />
    				</dataSource>
    			</environment>
    		</environments>
    	</configuration>
    

    5.创建与表对象的关系映射Mapping文件编写sql语句

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="myTest">
        <!--根据cust_id查询客户-->
        <select id="queryCustomerById" parameterType="Int" resultType="com.le.domain.Customer">
    	  SELECT * FROM `customer` WHERE cust_id  = #{cust_id}
    	</select>
    </mapper>
    

    6.在SqlMappingConfig.xml核心配置文件当中引入Mapping

    <!--加载映射文件-->
    <mappers>
          <mapper resource="com/le/domain/Customer.xml"></mapper>
    </mappers>
    

    7.创建工厂,执行sql语句

    @Test
    public void test() throws IOException {
       /* //1.sqlSessionFactoryBuilder 加载配置文件
    	SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    	
    	//2.读取配置文件
    	InputStream resourceAsStream = Resources.getResourceAsStream("SqlMappingConfig.xml");
    	
    	//3.获取session工厂
    	SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
    	
    	//4.获取会话   ---JDBC 连接
    	SqlSession sqlSession = sessionFactory.openSession();*/
    	SqlSession sqlSession = MybatisUtils.openSession();
    	
    	//5.执行sql
    	Customer customer = sqlSession.selectOne("queryCustomerById", 2);
    	System.out.println(customer);
    	
    	//6.关闭session
    	sqlSession.close();
    }
    

    MyBatis核心Api

    SqlSessionFactoryBuilder

    • SqlSessionFactoryBuilder用于创建SqlSessionFacoty
    • SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了
    • 因为SqlSession是通过SqlSessionFactory创建的
    • 所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

    SqlSessionFactory

    • 创建sqlSession的工厂,是一个接口
    • 接口中定义了openSession的不同重载方法
    • SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。

    SqlSession

    • 连接到数据库的一个会话
    • sqlSession中定义了数据库操作方法。
    • 每个线程都应该有它自己的SqlSession实例
    • SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围
    • 绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

    MyBatis架构

    MyBatis-查询

    MybatisUtils工具类

    package com.le.utils;
    
    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;
    
    public class MybatisUtils {
        public static final  SqlSessionFactory sessionFactory;
        static {
            //1.sqlSessionFactoryBuilder 加载配置文件
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            //2.读取配置文件
            InputStream resourceAsStream = null;
            try {
                resourceAsStream = Resources.getResourceAsStream("SqlMappingConfig.xml");
            } catch (IOException e) {
                e.printStackTrace();
            }
            //3.获取session工厂
            sessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
        }
    
        public static SqlSession openSession(){
            return sessionFactory.openSession();
        }
    }
    

    查询所有客户

    <!--查询所有-->
    <select id="queryAllCustomer" resultType="com.le.domain.Customer">
       SELECT * FROM `customer`
    </select>
    
    @Test
    public void test2() {
    	SqlSession sqlSession = MybatisUtils.openSession();
    	/*查询所有的用户*/
    	List<Customer> queryAllCustomer = sqlSession.selectList("queryAllCustomer");
    	for (Customer customer : queryAllCustomer) {
    		System.out.println(customer);
    	}
    	sqlSession.close();
    }
    

    根据用户名模糊查询客户

    方式1

    <!--根据用户名模糊查询客户-->
    <select id="querytCustomerByName" parameterType="String" resultType="com.le.domain.Customer">
    	select * from customer where cust_name like '%{value}%';
    </select>
    

    @Test
    public void test3(){
    	SqlSession sqlSession = MybatisUtils.openSession();
    	List<Customer> customers = sqlSession.selectList("querytCustomerByName", "%李%");
    	for (Customer customer : customers) {
    		System.out.println(customer);
    	}
    	sqlSession.close();
    }
    


    方式2

    <!--根据用户名模糊查询客户-->
    <select id="querytCustomerByName" parameterType="String" resultType="com.le.domain.Customer">
    	select * from customer where cust_name like #{name};
    </select>		
    

    总结

    parameterType
    	指定输入参数类型
    	mybatis通过ognl从输入对象中获取参数值拼接在sql中
    resultType
    	指定输出结果类型
    	mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中
    selectOne
    	查询一条记录
    	如果使用selectOne查询多条记录则抛出异常
    selectList
    	可以查询一条或多条记录
    #{}和${}
    	#{}
    		表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值
    		自动进行java类型和jdbc类型转换
    		#{}可以有效防止sql注入
    		#{}可以接收简单类型值或pojo属性值
    		如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称
    	${}
    		表示拼接sql串
    		通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换
    		${}可以接收简单类型值或pojo属性值
    		如果parameterType传输单个简单类型值,${}括号中只能是value
    

    保存更新删除

    添加客户,返回添加过后自增的主键

    <!--添加-->
    <insert id="insertCustom" parameterType="com.le.domain.Customer">
    	/*获取插入的最后一个id*/
    	<selectKey keyColumn="cust_id" keyProperty="cust_id" resultType="Integer" order="AFTER">
    		select last_insert_id()
    	</selectKey>
    
    	insert into `customer`(cust_name,cust_profession,cust_phone,email)
    	values (#{cust_name},#{cust_profession},#{cust_phone},#{email})
    </insert>	
    
    /*添加客户*/
    @Test
    public void insert(){
        SqlSession sqlSession = MybatisUtils.openSession();
        Customer customer = new Customer();
        customer.setCust_name("后裔2");
        customer.setCust_phone("18907897879");
        sqlSession.insert("insertCustom",customer);
        //当要改动数据库当中的记录时,执行sql时要自己提交事务
        //手动提交事务
        sqlSession.commit();
        System.out.println(customer.getCust_id());
        sqlSession.close();
    }
    

    更新客户

    <!--更新-->
    <update id="updateCustomer" parameterType="com.le.domain.Customer">
    	update `customer` set cust_name=#{cust_name} where cust_id=#{cust_id}
    </update>
    

    /*更新操作*/
    @Test
    public void update(){
        SqlSession sqlSession = MybatisUtils.openSession();
        Customer customer = sqlSession.selectOne("queryCustomerById", 12);
        customer.setCust_name("孙悟空");
        sqlSession.update("updateCustomer",customer);
        sqlSession.commit();
        sqlSession.close();
    }
    


    删除客户

    <!--删除操作-->
    <delete id="deleteCustomer" parameterType="com.le.domain.Customer">
    	delete from `customer` where cust_id=#{cust_id}
    </delete>	
    

    /*删除*/
    @Test
    public void delete(){
        SqlSession sqlSession = MybatisUtils.openSession();
        Customer customer = sqlSession.selectOne("queryCustomerById", 12);
        sqlSession.delete("deleteCustomer",customer);
        sqlSession.commit();
        sqlSession.close();
    }
    

    MyBatis开发DAO

    原始Dao开发方法

    package com.le.dao;
    
    import com.le.domain.Customer;
    import java.util.List;
    
    public interface CustomerDao {
        public Customer getCustomerWithId(Integer id);
        public List<Customer> getAllCustomer();
        public void addCustomer(Customer customer);
        public void  updateCustomer(Customer customer);
    }
    

    package com.le.dao;
    
    import com.le.domain.Customer;
    import com.le.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    
    import java.util.List;
    
    public class CustomerDaoImpl implements CustomerDao {
        @Override
        public Customer getCustomerWithId(Integer id) {
            SqlSession sqlSession = MybatisUtils.openSession();
            Customer customer = sqlSession.selectOne("queryCustomerById", id);
            return customer;
        }
    
        @Override
        public List<Customer> getAllCustomer() {
            SqlSession sqlSession = MybatisUtils.openSession();
            List<Customer> customers = sqlSession.selectList("queryAllCustomer");
            return customers;
        }
    
        @Override
        public void addCustomer(Customer customer) {
            SqlSession sqlSession = MybatisUtils.openSession();
            sqlSession.insert("insertCustom",customer);
        }
    
        @Override
        public void updateCustomer(Customer customer) {
            SqlSession sqlSession = MybatisUtils.openSession();
            sqlSession.update("insertCustom",customer);
        }
    }
    

    @Test
    public void test() throws IOException {
        //1.sqlSessionFactoryBuilder 加载配置文件
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //2.读取配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMappingConfig.xml");
        //3.获取session工厂
        SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
        //4.获取会话   ---JDBC 连接
        SqlSession sqlSession = sessionFactory.openSession();
    
        //5.执行sql
        Customer customer = sqlSession.selectOne("queryCustomerById", 2);
        System.out.println(customer);
        //6.关闭session
        sqlSession.close();
    }
    


    Mapper动态代理

    要求

    • namespace必须和Mapper接口类路径一致
    • id必须和Mapper接口方法名一致
    • parameterType必须和接口方法参数类型一致
    • resultType必须和接口方法返回值类型一致

    过程

    package com.le.mapper;
    
    import com.le.domain.Customer;
    import java.util.List;
    
    public interface CustomerMapper {
        //根据cust_id查询客户
        public Customer queryCustomerById(Integer id);
    }	
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.le.mapper.CustomerMapper">
        <!--根据cust_id查询客户-->
        <select id="queryCustomerById" parameterType="Integer"
                resultType="com.le.domain.Customer">
    	  SELECT * FROM `customer` WHERE cust_id  = #{cust_id}
    	</select>
    </mapper>		
    
    @Test
    public void test(){
     SqlSession sqlSession = MybatisUtils.openSession();
            CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
            Customer customer = mapper.queryCustomerById(1);
            System.out.println(customer);
            sqlSession.close();
    }
    

    selectOne和selectList

    • 动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定
    • 如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

    参数传递

    单个参数

    • 可以接受基本类型,对象类型,集合类型的值。
    • MyBatis可直接使用这个参数,不需要经过任何处理。

    多个参数

    • 任意多个参数,都会被MyBatis重新包装成一个Map传入。
    • Map的key是param1,param2…,值就是参数的值。

    ​ 示例

    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
    	Customer customer = mapper.queryCustomerById(1,"鲁班大师");
        System.out.println(customer);
        sqlSession.close();
    }
    

    <!--根据cust_id 和 cust_name查询客户-->
    <select id="queryCustomerById"
    		resultType="com.le.domain.Customer">
      SELECT * FROM `customer` WHERE cust_id  = #{arg0} and cust_name=#{arg1}
    </select>
    


    @param命名参数

    • 为参数使用@Param起一个名字,
    • MyBatis就会将这些参数封装进map中,key就是我们自己指定的名字

    ​ 示例

    public interface CustomerMapper {
        /*
        * 根据cust_id查询客户
        * */
        public Customer queryCustomerById(@Param("cust_id") Integer id,@Param("cust_name") String cust_name);
    }
    
    <!--根据cust_id 和 cust_name查询客户-->
    <select id="queryCustomerById"
    		resultType="com.le.domain.Customer">
      SELECT * FROM `customer` WHERE cust_id  = #{arg0} and cust_name=#{arg1}
    </select>
    

    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
    	Customer customer = mapper.queryCustomerById(1,"鲁班大师");
        System.out.println(customer);
        sqlSession.close();
    }
    

    POJO

    • 当这些参数属于我们业务POJO时,我们直接传递POJO

    ​ 示例

    public void insertCustom(Customer customer);	
    

    @Test
    public void insert(){
        SqlSession sqlSession = MybatisUtils.openSession();
        Customer customer = new Customer();
        customer.setCust_name("后裔2");
        customer.setCust_phone("18907897879");
        sqlSession.insert("insertCustom",customer);
        //当要改动数据库当中的记录时,执行sql时要自己提交事务
        //手动提交事务
        sqlSession.commit();
        System.out.println(customer);
        sqlSession.close();
    }
    

    <!--添加-->
    <insert id="insertCustom" parameterType="com.le.domain.Customer">
    	insert into `customer`(cust_name,cust_profession,cust_phone,email)
    	values (#{cust_name},#{cust_profession},#{cust_phone},#{email})
    </insert>
    

    Map

    • 我们也可以封装多个参数为map,直接传递

    ​ 示例

    public Customer queryCustomerById(Map<String,Object> map);
    

    @Test
    public void test(){
    	SqlSession sqlSession = MybatisUtils.openSession();
    	CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
    	HashMap<String, Object> hashMap = new HashMap<>();
    	hashMap.put("cust_id",1);
    	hashMap.put("cust_name","鲁班");
    	Customer customer = mapper.getCustomerWithID(hashMap);*/
    	System.out.println(customer);
    	sqlSession.close();
    }
    
    <!--根据cust_id 和 cust_name查询客户-->
    <select id="queryCustomerById"
    		resultType="com.le.domain.Customer">
      SELECT * FROM `customer` WHERE cust_id  = #{cust_id} and cust_name=#{cust_name}
    </select>	
    

    参数传递源码分析

    • 会把参数给放到一个数组当中

    • 如果一个参数, 内部处理时,会自动把该参数范围

    • 如果是多个参数,内部会做判断

    • 判断是否有@param注解

    ​ 如果没有@param注解
    ​ 没有注解的话, 就直接使用arg0 arg1...为key 放到map中

    ​ 并且还会以param1和param2...为key放一份到map中

    ​ 如果有@param注解
    ​ 如果有注解的话, 会使用注解当中的值,替换掉默认的arg0和arg1
    ​ 使用@param中的值,做为key 放到一个map当中
    ​ 并且还会以param1和param2...为key放一份到map中

    MaBatis核心配置文件

    properties标签

    • 定义属性及读取属性文件

    ​ 示例

    <!-- 是用resource属性加载外部配置文件 -->
    <properties resource="db.properties">
    	<!-- 在properties内部用property定义属性 -->
    	<!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 -->
    	<property name="driver" value="com.mysql.jdbc.Driver" />
    	<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
    	<property name="username" value="root" />
    	<property name="password" value="1234" />
    </properties>
    

    settings标签

    • 这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为

    ​ 示例

    package com.le.domain;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    @Setter@Getter@ToString
    public class Customer {
        private Integer cust_id;
        private String cust_name;
        private String cust_profession;
        private String cust_phone;
        private String email;
    }
    

    <!-- 用来配置MyBatis中一些设置 -->
    <!-- 开启驼峰映射,为自定义的SQL语句服务 -->
    <!-- 设置其用数据库字段下划线映射到jaba对象的驼峰式命名属性,默认为false -->
    <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--开启驼峰命名法-->
    	<setting name="mapUnderscoreToCamelCase" value="true">
    </settings>
    

    typeAliases标签

    • 类型别名是为 Java 类型设置一个短的名字
    • 定义单个别名
    <!--定义别名-->
    <typeAliases>
        <!--单个别名定义-->
        <typeAlias alias="Customer" type="com.le.domain.Customer"/>
    </typeAliases>		
    

    <!--查询用户 ID-->
    <select id="getCustomerWithID"  resultType="Customer" >
    	select * from `customers` where cust_id = #{id} and cust_name=#{name}
    </select>
    

    • 批量别名定义

      ​ 如果当前包类与子包类重名,会有异常
      ​ 可以在类上使用注解@Alias("别名")

    <!--定义别名-->
    <typeAliases>
        <!--批量定义别名, 别名为类名(大小写不敏感)-->
        <package name="com.le.domain"/>
    </typeAliases>	
    

    typeHandlers标签

    • 无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,
    • 还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
    • JDK1.8之后实现全部的JSR310规范
    • 日期时间处理上,我们可以使用MyBatis基于JSR310(Date and Time API)
    • 编写的各种日期时间类型处理器。
    • MyBatis3.4以前的版本需要我们手动注册这些处理器,以后的版本都是自动注册的

    Plugins标签

    • 插件是MyBatis提供的一个非常强大的机制,
    • MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。
    • 通过插件来修改MyBatis的一些核心行为。

    Environments标签

    • MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置。
    • 每种环境使用一个environment标签进行配置并指定唯一标识符
    • 可以通过environments标签中的default属性指定一个环境的标识符来快速的切换环境
    • Environment子标签

    transactionManager事务管理
    	Type有以下取值
    	JDBC
    		使用JDBC 的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围
    	MANAGED
    		不提交或回滚一个连接、让容器来管理事务的整个生命周期
    		ManagedTransactionFactory
    	自定义
    		实现TransactionFactory接口 
    		type=全类名/别名
    		
    dataSource数据源
    	type有以下取值
    	UNPOOLED
    		不使用连接池UnpooledDataSourceFactory
    	POOLED
    		使用连接池PooledDataSourceFactory
    	JNDI
    		在EJB 或应用服务器这类容器中查找指定的数据源
    	自定义
    		实现DataSourceFactory接口,定义数据源的获取方式
    		
    实际开发
    	实际开发中我们使用Spring管理数据源
    	并进行事务控制的配置来覆盖上述配置 
    
    <!-- spring整合后 environments配置将废除 使用spring中的连接池 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    
        <environment id="test">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    

    databaseIDProvider标签

    ​ MyBatis 可以根据不同的数据库厂商执行不同的语句。
    ​ 可以通过databaseIDProvider标签来进行设置

    <databaseIdProvider type="DB_VENDOR">
    	<property name="MYSQL" value="mysql"/>
    	<property name="DB2" value="db2"/>
    	<property name="Oracle" value="oracle" />
    	<property name="SQL Server" value="sqlserver"/>
    </databaseIdProvider>
    

    ​ 示例

    <!--查询用户 ID-->
    <select id="getAllCustomer"  resultType="Customer" databaseId="mysql">
    	select * from `customers`
    </select>		
    

    mappers标签

    resource属性

    ​ 使用相对于类路径的资源

    <!--加载映射文件-->
    <mappers>
        <mapper resource="com/le/mapping/CustomerMapping.xml"></mapper>
    </mappers>		
    

    class属性

    • 使用mapper接口类路径
    • 此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
    <!--加载映射文件-->
    <mappers>
        <mapper class="com.le.mapping.CustomerMapping"></mapper>
    </mappers>	
    

    package子标签

    • 指定包下的所有mapper接口
    • 此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
    <!--加载映射文件-->
    <mappers>
        <package name="com.le.mapping"/>
    </mappers>	
    

    输出类型

    输出简单类型

    <!--查询总数-->
    <select id="getAccountCustomer" resultType="Integer">
    	select count(*) from customer;
    </select>
    

    Map

    第1种形式

    • key:是列名

    • value:是列名对应的值

      示例

    public Map<String,Object> getCustomerWithId(Integer id);
    
    <select id="getCustomerWithId" resultType="java.util.Map">
    	select * from customer where cust_id=#{id}
    </select>
    
    @Test
    public void test(){
    	SqlSession sqlSession = MybatisUtils.openSession();
    	CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
    	Map<String, Object> customer = customerMapper.getCustomerWithId(2);
    	System.out.println(customer);
    	sqlSession.close();
    }
    

    第2种形式

    • Map<key,自定义对象>
    • key为自己指定的数据库中的列值

    ​ 示例

    @MapKey("cust_name")
    public Map<Integer,Customer> getAllCustomer();
    

    <select id="getAllCustomer" resultType="com.le.domain.Customer">
    	select * from customer;
    </select>
    

    @Test
    public void test(){
    	SqlSession sqlSession = MybatisUtils.openSession();
    	CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
    	Map<Integer, Customer> allCustomer = customerMapper.getAllCustomer();
    	for(Integer integer:allCustomer.keySet())
    	{
    		System.out.println("key="+integer+" value="+allCustomer.get(integer));
    	}
    	sqlSession.close();
    }
    


    resultMap

    • 只有在写输出时使用的都是resultType
    • 但是resultType要求必须得要字段名称和数据库当中的名称一致时才能有值,否则为null
    • 如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系
    • 表名与domain
    package com.le.domain;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    @Setter@Getter@ToString
    public class Customer {
        private Integer cust_ids;
        private String cust_names;
        private String cust_professions;
        private String cust_phones;
        private String email;
    }
    

    <resultMap id="customerMap" type="Customer">
    	<id column="cust_id" property="cust_ids"/>
    	<result column="cust_name" property="cust_names"/>
    	<result column="cust_profession" property="cust_professions"/>
    	<result column="cust_phone" property="cust_phones"/>
    	<result column="email" property="email"/>
    </resultMap>
    
    <select id="getCustomer" resultMap="customerMap">
    	select * from customer where cust_id=#{id}
    </select>
    

    @Test
    public void test(){
    	SqlSession sqlSession = MybatisUtils.openSession();
    	CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
    	Customer customer = customerMapper.getCustomer(2);
    	System.out.println(customer);
    	sqlSession.close();
    }
    



    多表操作

    ManyToOne

    关系表

    查询

    分步查询
    第一步 先查出所有的订单
    <resultMap id="myOrder" type="Order">
    	<id property="order_id" column="order_id"/>
    	<result property="order_name" column="order_name"/>
    	<result property="order_num" column="order_name"/>
    	<!--分步查询-->
    	<association property="customer" javaType="Customer"
    				 select="com.le.mapper.CustomerMapper.getCustomerWithId"
    				 column="cust_id">
    	</association>
    </resultMap>
    
    <select id="getOrders" resultMap="myOrder">
    	select * from `order`
    </select>				
    
    第二步 根据id查出对应客户
    <mapper namespace="com.le.mapper.CustomerMapper">
    	<!--根据id获取客户-->
    	<select id="getCustomerWithId" resultType="com.le.domain.Customer">
    		SELECT * from customer WHERE cust_id = #{id}
    	</select>
    </mapper>		
    

    左连接查询
    查询所有的订单及订单所对应的客户
    • 左连接
    • 把左边表的数据全部查出,右边表只查出满足条件的记录
    应对sql
    SELECT * FROM `order` as o LEFT JOIN customer as c on o.cus_id = c.cust_id;
    
    建立domain
    package com.le.domain;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    @Setter@Getter@ToString
    public class Order {
        private Integer order_id;
        private String order_name;
        private String order_num;
        private Customer customer;
    }
    
    建立Mapping映射
    <resultMap id="orderMap" type="Order">
        <id property="order_id" column="order_id"/>
        <result property="order_name" column="order_name"/>
        <result property="order_num" column="order_name"/>
        <!--关联对象赋值-->
        <association property="customer" javaType="Customer">
            <id property="cust_id" column="cust_id"/>
            <result property="cust_name" column="cust_name"/>
            <result property="cust_profession" column="cust_profession"/>
            <result property="cust_phone" column="cust_phone"/>
            <result property="email" column="email"/>
        </association>
    </resultMap>
    
    <!--查询所有订单-->
    <select id="getAllOrders" resultMap="orderMap">
        SELECT * from `order` as o LEFT JOIN `customer` c on o.cust_id = c.cust_id;
    </select>	
    

    测试类

    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.openSession();
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        List<Order> allOrders = orderMapper.getAllOrders();
        for (Order order : allOrders) {
            System.out.println(order);
        }
        sqlSession.close();
    }
    
    分部查询懒加载

    <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载-->
    <setting name="aggressiveLazyLoading" value="false"/>
    <!--指定哪个对象的方法触发一次延迟加载。-->
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode"/>
    

    添加

    添加客户

    <!--保存客户-->
    <insert id="insertCustomer" parameterType="Customer"
            useGeneratedKeys="true"
            keyColumn="cust_id"
            keyProperty="cust_id">
        insert into `customer`(cust_name,cust_profession,cust_phone,email)
        values (#{cust_name},#{cust_profession},#{cust_phone},#{email})
    </insert>
    
    设置关系(外键没有赋值上)
    @Test
    public void test(){
    	SqlSession sqlSession = MybatisUtils.openSession();
    	CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
    	OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    	
    	Customer customer = new Customer();
    	customer.setCust_name("新客户001");
    	customer.setCust_phone("137090909090");
    	customer.setEmail("123123@163.com");
    	customer.setCust_profession("新职业001");
    
    	/*先添加客户  获取客户生成的id  再去添加订单*/
    	customerMapper.insertCustomer(customer);
    
    	Order order = new Order();
    	order.setOrder_name("新订单001");
    	order.setOrder_num("20000001001");
    	/*设置关系 */
    	order.setCustomer(customer);
    	System.out.println(customer);
    	/*保存订单*/
    	orderMapper.insertOrder(order);
    	sqlSession.commit();
    	sqlSession.close();
    }
    
    添加订单
    <!--保存订单-->
    <!-- useGeneratedKeys="true"把新增加的主键赋值到自己定义的keyProperty(id)中 -->
    <insert id="insertOrder" 
    		parameterType="Order"
            useGeneratedKeys="true"
            keyColumn="order_id"
            keyProperty="order_id">
        insert into `order`(order_name,order_num,cust_id)
        values (#{order_name},#{order_num},#{customer.cust_id})
    </insert>
    

    OnToMany

    查询

    查询客户和客户订单

    sql语句
    SELECT * FROM customer as c LEFT JOIN `order` as o  on c.cust_id = o.cust_id;
    
    映射

    <resultMap id="custMap" type="Customer">
        <id column="cust_id" property="cust_id"/>
        <result column="cust_name" property="cust_name"/>
        <result column="cust_profession" property="cust_profession"/>
        <result column="cust_phone" property="cust_phone"/>
        <result column="email" property="email"/>
        <collection property="orders" ofType="Order">
            <id column="order_id" property="order_id"/>
            <id column="order_name" property="order_name"/>
            <id column="order_num" property="order_num"/>
        </collection>
    </resultMap>
    <!--查询所有客户-->
    <select id="getAllCustomers" resultMap="custMap">
        select* from `customer` as c LEFT JOIN `order` as o ON c.cust_id = o.cust_id;
    </select>
    
    测试

    @Test
    public void test4(){
        /*查询所有客户*/
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        List<Customer> allCustomers = customerMapper.getAllCustomers();
        for (Customer allCustomer : allCustomers) {
            System.out.println(allCustomer);
        }
        sqlSession.close();
    }
    

    添加

    保存数据
    /*保存客户*/
    public void insertCustomer(Customer customer);
    

    <!--保存客户-->
    <insert id="insertCustomer" 
    		parameterType="Customer"
            useGeneratedKeys="true"
            keyColumn="cust_id"
            keyProperty="cust_id">
        insert into `customer`(cust_name,cust_profession,cust_phone,email)
        values (#{cust_name},#{cust_profession},#{cust_phone},#{email})
    </insert>
    

    /*保存订单*/
    public void insertOrder(Order order);
    

    <!--保存订单-->
    <!-- useGeneratedKeys="true"把新增加的主键赋值到自己定义的keyProperty(id)中 -->
    <insert id="insertOrder" 
    		parameterType="Order"
            useGeneratedKeys="true"
            keyColumn="order_id"
            keyProperty="order_id">
        insert into `order`(order_name,order_num,cust_id)
        values (#{order_name},#{order_num},#{customer.cust_id})
    </insert>	
    
    维护外键

    /*更新与客户的关系*/
    public void updateCustId(@Param("orderId") Integer orderId, @Param("custId") Integer custId);		
    
    <!--更新关系-->
    <update id="updateCustId">
        update `order` set `cust_id`=#{custId} where `order_id`=#{orderId}
    </update>
    
    管理关系
    @Test
    public void test5(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        Customer customer = new Customer();
        customer.setCust_name("新客户");
    
        Order order1 = new Order();
        order1.setOrder_name("订单2");
    
        Order order2 = new Order();
        order2.setOrder_name("订单2");
    
        customer.getOrders().add(order1);
        customer.getOrders().add(order2);
    
        /*保存数据*/
        customerMapper.insertCustomer(customer);
        orderMapper.insertOrder(order1);
        orderMapper.insertOrder(order2);
    
        /*更新关系*/
        for (Order order : customer.getOrders()) {
            orderMapper.updateCustId(order.getOrder_id(),customer.getCust_id());
        }
        sqlSession.commit();
        sqlSession.close();
    }			
    

    删除

    • 删除时一定要先打破关系再做删除操作

      示例

    /*根据id删除客户*/
    public void deleteCustomer(Integer id);		
    

    <!--根据id删除客户-->
    <delete id="deleteCustomer">
        delete from `customer` where cust_id=#{id}
    </delete>
    
    /*打破跟客户关系*/
    public void updateRelationCustomer(Integer custId);
    
    <!--打破跟客户关系-->
    <update id="updateRelationCustomer">
        update `order` set cust_id=null where cust_id=#{custId}
    </update>	
    

    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        //一对多删除之前  要先打破关系
        orderMapper.updateRelationCustomer(36);
        /*删除客户*/
        customerMapper.deleteCustomer(36);
        sqlSession.commit();
        sqlSession.close();
    }
    



    ManyToMany

    关系表

    package com.le.domain;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Setter@Getter@ToString
    public class Teacher {
        private Integer teacher_id;
        private String teacher_name;
        private List<Student> students = new ArrayList<>();
    }
    
    package com.le.domain;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    @Setter@Getter @ToString
    public class Student {
        private Integer stu_id;
        private String stu_name;
    }
    

    查询

    分步查询
    查询出指定的老师
    public interface TeacherMapper {
        /*查询指定的老师*/
        public Teacher getTeacherWithId(Integer id);
    }
    
    <!--查询指定的老师-->
    <select id="getTeacherWithId" resultMap="teacherMap2">
        SELECT * from teacher WHERE teacher_id = #{id};
    </select>
    <resultMap id="teacherMap2" type="Teacher">
        <id column="teacher_id" property="teacher_id"/>
        <result column="teacher_name" property="teacher_name"/>
        <collection property="students" ofType="Student"
                    select="com.le.mapper.StudentMapper.getStuByTeach"
                    column="teacher_id"/>
    </resultMap>	
    
    根据老师id查询出所有学生
    public interface StudentMapper {
        /*根据老师id查询学生*/
        public List<Student>getStuByTeach(Integer id);
    }
    

    <select id="getStuByTeach" resultType="com.le.domain.Student">
          SELECT * from student where stu_id in(SELECT stu_id from stu_teacher_rel where teacher_id = #{id})
    </select>		
    

    查询

    @Test
    public void test2(){
        SqlSession sqlSession = MybatisUtils.openSession();
        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = teacherMapper.getTeacherWithId(2);
        System.out.println(teacher);
        sqlSession.close();
    }		
    
    左边接查询
    public interface TeacherMapper {
        /*查询老师  并且把关联的学生也查出来*/
        public List<Teacher>getAllTeachers();
    }
    

    <mapper namespace="com.le.mapper.TeacherMapper">
        <!-- 查询老师  并且把关联的学生也查出来 -->
        <resultMap id="teacherMap" type="Teacher">
            <id column="teacher_id" property="teacher_id"/>
            <result column="teacher_name" property="teacher_name"/>
            <collection property="students" javaType="list" ofType="Student">
                <id column="stu_id" property="stu_id"/>
                <result column="stu_name" property="stu_name"/>
            </collection>
        </resultMap>
    
        <select id="getAllTeachers" resultMap="teacherMap">
            SELECT*FROM teacher as t
            LEFT JOIN stu_teacher_rel as r on t.teacher_id = r.teacher_id
            LEFT JOIN student as s ON r.stu_id = s.stu_id
        </select>
    </mapper>
    

    添加

    添加老师
    /*保存老师*/
    public void insertTeacher(Teacher teacher);
    
    <!--保存老师-->
    <insert id="insertTeacher" parameterType="Teacher"
            useGeneratedKeys="true"
            keyProperty="teacher_id"
            keyColumn="teacher_id">
        insert into`teacher`(teacher_name) values (#{teacher_name})
    </insert>
    
    添加学生
    /*保存学生*/
    public void insertStudent(Student student);
    
    <!--保存学生-->
    <insert id="insertStudent" parameterType="Student"
            useGeneratedKeys="true"
            keyProperty="stu_id"
            keyColumn="stu_id">
        insert into `student` (stu_name) values (#{stu_name})
    </insert>	
    
    添加中间关系
    /*插入关系表*/
    public void insertRelation(@Param("stuId") Integer stuId, @Param("teacherId") Integer teacherId);
    
    <!-- 插入关系表 -->
    <insert id="insertRelation">
        insert into stu_teacher_rel (stu_id,teacher_id) values (#{stuId},#{teacherId})
    </insert>	
    

    动态sql

    什么是动态sql

    ​ 通过mybatis提供的各种标签方法实现动态拼接sql。

    if标签

    需求

    根据客户名和职业查询客户
    /*根基客户名称和职业来查询*/
    public List<Customer> getCustomer(@Param("name") String name, @Param("profession") String profession);
    
    <select id="getCustomer" 
    		resultType="com.le.domain.Customer">
    	select from customer where cust_name=#{name} ad cust_profession=#{profession}
    </select>	
    
    存在问题
    • 有可能传入的名称或级别为空
    • 可以使用if标签来进行判断
    • 如果前一个条件后面多一个and执行就会报错(也就是说需要将and分布合理)
    <!--if标签:符合条件会自动把if中的内容拼接到sql之后-->
    <select id="getCustomer" 						resultType="com.le.domain.Customer">
        select * from `customer` where
    	<if test="name != null and name != ''">
    	  `cust_name`=#{name}
    	</if>
    	<if test="profession != null and profession!=''">
    	  and `cust_profession`=#{profession}
    	</if>
    </select>
    

    Where标签

    • 去掉第一个前And
    <!--where标签:会自动生成和删除where  
    	还能删除where后第1个and  
    	条件前and去掉 -->
    <select id="getCustomer2"
    	resultType="com.le.domain.Customer">
    	select * from `customer`
    	<where>
    		<if test="name != null and name != ''">
    		  and `cust_name`=#{name}
    		</if>
    		<if test="profession != null and profession!=''">
    		  and `cust_profession`=#{profession}
    		</if>
    	</where>
    </select>
    

    trim标签

    <!--trim标签:
       prefix:设置前缀  在第一个条件之前加一个前缀
       prefixOverrides: 条件前缀覆盖 把第一个条件之前的and变成空
       suffix: 设置后缀 在最后一个条件之后加一个后缀
       suffixOverrides: 条件后缀覆盖  把最后一个条件之后的and变成空
    -->
    <select id="getCustomer3"
    	resultType="com.le.domain.Customer">
        select * from `customer`
        <trim prefix="where" prefixOverrides="and" suffixOverrides="and" >
            <if test="name != null and name != ''">
                and `cust_name`=#{name} and
            </if>
            <if test="profession != null and profession!=''">
               `cust_profession`=#{profession} and
            </if>
        </trim>
    </select>
    

    choose标签

    <!--
        choose   只要第一个条件满足,后面条件都不执行
        when
        otherwise
    -->
    <select id="getCustomer" resultType="com.le.domain.Customer">
        <include refid="selectID"/>
        <where>
            <choose>
                <when test="profession != null and profession!=''">
                    `cust_profession`=#{profession}
                </when>
                <when test="name != null and name != ''">
                    `cust_name`=#{name}
                </when>
                <otherwise>1=1</otherwise>
            </choose>
        </where>
    </select>
    

    set标签

    <!--
        set标签:会添加update 中 set  并且它会把最后一个,去掉
    -->
    <!--更新客户-->
    <update id="updateCustomer">
        update `customer`
        <set>
            <if test="cust_name != null and cust_name !='' ">
                cust_name=#{cust_name},
            </if>
            <if test="cust_profession != null and cust_profession !='' ">
                cust_profession=#{cust_profession},
            </if>
        </set>
        where cust_id=#{cust_id}
    </update>
    

    foreach标签

    查询条件值为指定的值当中

    <select id="queryCustomerIn"
    	resultType="com.le.domain.Customer">
    	<include refid="selectID"/>where `cust_id` in(2,3,5,6);
    </select>
    <!--注意 在include当中定义的property 取的时候 要使用${} -->
    <sql id="selectID">
    	<choose>
    		<when test="${lk} == 2">
    			select cust_name from `customer`
    		</when>
    		<otherwise>
    			select * from `customer`
    		</otherwise>
    	</choose>
    </sql>
    

    给定的值可以以三种形式给出
    数组

    /*根据id查询指定的客户 多个客户*/
    public List<Customer> getCustomers(Integer[] array);
    
    @Test
    public void test(){
    	SqlSession sqlSession = MybatisUtils.openSession();
    	CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
    	Integer[] ids = new Integer[4]{2,3,5,6};
    	List<Customer> customers = customerMapper.getCustomers(ids);
    	for (Customer customer : customers) {
    		System.out.println(customer);
    	}
    	sqlSession.close();
    }
    
    <select id="getCustomers" 
    	parameterType="Integer[]" resultType="com.le.domain.Customer">
    	select * from `customer` where `cust_id` in
    	<foreach collection="array" open="(" close=")" separator="," item="item">
    		#{item}
    	</foreach>
    </select>
    

    List
    <select id="getCustomers" 
    	parameterType="List" resultType="com.le.domain.Customer">
    	select * from `customer` where `cust_id` in
    	<foreach collection="list" open="(" close=")" separator="," item="item">
    		#{item}
    	</foreach>
    </select>
    
    @Test
    public void test(){
    	SqlSession sqlSession = MybatisUtils.openSession();
    	CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
    	ArrayList<Integer> list = new ArrayList<>();
    	list.add(2);
    	list.add(3);
    	list.add(4);
    	list.add(6);
    	List<Customer> customers = customerMapper.getCustomers(list);
    	for (Customer customer : customers) {
    		System.out.println(customer);
    	}
    	sqlSession.close();
    }
    

    包装类VO

    ​ 创建Vo

    package com.le.domain;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import java.util.List;
    
    @Setter@Getter@ToString
    public class QueryVo {
        private Integer[] ids;
        private List<Integer> idList;
    }			
    


    ​ 测试

    <select id="getCustomers" 
    	parameterType="QueryVo" resultType="com.le.domain.Customer">
    	<include refid="selectID"/> where `cust_id` in
    	<foreach collection="idList" open="(" close=")" separator="," item="ids">
    		#{ids}
    	</foreach>
    </select>
    
    @Test
    public void test(){
    	SqlSession sqlSession = MybatisUtils.openSession();
    	CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
    
    	QueryVo queryVo = new QueryVo();
    	queryVo.setIds(new Integer[]{2,3,4,5});
    	ArrayList<Integer> arrayList = new ArrayList<>();
    	arrayList.add(2);
    	arrayList.add(3);
    	arrayList.add(4);
    	arrayList.add(6);
    	queryVo.setIdList(arrayList);
    	List<Customer> customers = customerMapper.getCustomers(queryVo);
    	for (Customer customer : customers) {
    		System.out.println(customer);
    	}
    	sqlSession.close();
    }
    

    bind标签

    <!--
        bind标签:可以取出传入的值,重新处理, 赋值给别外一个值
     -->
    <select id="getCustomerWithId" resultType="Customer">
        <bind name="newId" value="id+2"/>
        <include refid="selectID">
            <property name="lk" value="2"/>
        </include>  where cust_id=#{newId}
    </select>
    

    Sql片段

    • Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
    <select id="getCustomerWithId" resultType="Customer">
        <include refid="selectID">
            <property name="lk" value="2"/>
        </include>  where cust_id=#{id}
    </select>
    
    <!--注意 在include当中定义的property 取的时候 要使用${} -->
    <sql id="selectID">
        <choose>
            <when test="${lk} == 2">
                select cust_name from `customer`
            </when>
            <otherwise>
                select * from `customer`
            </otherwise>
        </choose>
    </sql>
    

    缓存

    一级缓存

    缓存介绍

    • MyBatis中使用缓存来提高其性能。
    • 当查询数据时, 会先从缓存中取出数据,如果缓存中没有,再到数据库当中查询
    • MyBatis中的缓存分为两种:一级缓存和二级缓存
    • 一级缓存是sqlSession级别的,二级缓存是mapper级别的

    一级缓存

    • 本地缓存 (默认开启)
    • 在sqlSession没有关闭之前,再去查询时, 会从缓存当中取出数据,不会重新发送新的sql

    一级缓存失效

    • 如果在查询之前,执行了增删改 缓存就会失效
    • 手动清空缓存
    • 如果两次的查询条件不一样,缓存也会失效
    • 如果两个查询在不同的sqlsession当中

    二级缓存

    二级缓存介绍

    ​ 全局作用域缓存 一个namespace对应一个缓存
    ​ 如果会话关闭,一级缓存的数据会被保存到二级缓存中
    ​ 不同namespace查出的数据 ,会放到自己对应的缓存中
    ​ 现在默认也是打开的

    二级缓存使用步骤

    ​ 1.确保在配置文件当中开启二级缓存
    ​ 2.在对应的mapper中添加cache标签

    eviction
    	回收策略
    flushInterval
    	刷新间隔
    	默认不清空
    readOnly
    	是否只读
    	true
    		告诉Mybatis是只读操作,不去修改数据
    		Mybatis为了加快获取速度,会直接将缓存的引用将给用, 不安全, 速度快
    	false
    		非只读,有可能修改数据
    		Mybatis会利用序列化和反序列化复制一份给你   速度慢些
    size
    	可以存放多少个元素
    type
    	可以用来指定自定义的缓存
    

    ​ 3.POJO需要实现Serializable接口

    注意事项

    • 查询的数据都会先放到一级缓存当中
    • 只有会话关闭,一级缓存中的数据才会转称到二级缓存中

    缓存相关属性

    cacheEnabled
    	只能控制二级缓存的开关
    select中useCache
    	控制的也是二级缓存是否使用
    增删改标签中flushCache
    	一级和二级都会被清空
    	增删改flushCache默认为true
    	查询flushCache默认为false
    sqlSession.clearCache()
    	只清除当前session的一级缓存
    localCacheScope
    	本地缓存作用域
    	取值
    		SESSION
    		STATEMENT
    	STATEMENT可以使用它禁用缓存
    

    缓存使用顺序

    • 先到二级缓存当中查找
    • 如果二级缓存中没有,就去找一级缓存
    • 如果一级缓存中也没有就去到数据库当中查询
  • 相关阅读:
    nginx centos 服务开机启动设置实例详解
    CentOS打开关闭永久防火墙指定端口
    使用 nginx 反向代理 sqlserver 访问 配置
    Springboot集成Mybatis
    linux中查看java进程
    mybatis关于jdbc连接报错,5.5.62MySQL连接,出现com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure等问题解决方法
    索引的分析
    MySQL慢查询分析工具
    MySQL锁
    nGrinder介绍、编写脚本与执行(完整版)
  • 原文地址:https://www.cnblogs.com/mumuyinxin/p/10967833.html
Copyright © 2020-2023  润新知