MyBatis

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

为什么要使用MyBatis?
    JDBC
        SQL夹在Java代码块里,耦合度高导致硬编码内伤
        维护不易且实际开发需求中sql是有变化,频繁修改的情况多见
        要自已创建connection、创建statement、手动设置参数、结果集检索等
    Hibernate
        长难复杂SQL,对于Hibernate而言处理也不容易
        内部自动生产的SQL,不容易做特殊优化。
        基于全映射的全自动框架,javaBean存在大量字段时无法只映射部分字段。导致数据库性能下降。
    Mybatis
        对开发人员而言,核心sql还是需要自己优化
        MyBatis是一个半自动化的持久化层框架。
        MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。

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


    2.    MyBatis-快速入门-配置文件
MyBatis入门程序
    1. 下载Mybatis核心包
        http://www.mybatis.org/mybatis-3/getting-started.html
        https://github.com/mybatis/mybatis-3/releases
    2.创建工程,引入MyBatis核心包及依赖包
mysql-connector-java-5.1.7
    3.创建customer表,建立与表对象的domain

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for customer
-- ----------------------------
DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer` (
  `cust_id` int(11) NOT NULL AUTO_INCREMENT,
  `cust_name` varchar(255) DEFAULT NULL,
  `cust_profession` varchar(255) DEFAULT NULL,
  `cust_phone` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of customer
-- ----------------------------
INSERT INTO `customer` VALUES ('1', '鲁班', '射手', '13499887733', '12341241@qq.com');
INSERT INTO `customer` VALUES ('2', '李白', '刺客', '18977665521', 'libai@163.com');
INSERT INTO `customer` VALUES ('3', '阿轲', '刺客', '18977665997', 'aike@qq.com');
INSERT INTO `customer` VALUES ('4', '德玛西亚', '肉盾', '13700997665', 'demaxiya.126.com6');
INSERT INTO `customer` VALUES ('5', '亚索', '战士', '13586878987', 'yasuo@qq.com');
INSERT INTO `customer` VALUES ('6', '奶妈', '辅助', '13398909089', 'nama@qq.com');
INSERT INTO `customer` VALUES ('7', '剑圣', '刺客', '13398909088', 'jiansheng@163.com');
INSERT INTO `customer` VALUES ('8', '盖伦', '肉盾', '15923242231', 'gailun@126.com');
INSERT INTO `customer` VALUES ('9', '锤石', '辅助', '13398908900', '8888@163.com');
INSERT INTO `customer` VALUES ('10', '阿木木', '辅助', '13398908928', '13398908928@qq.com');

使用@setter@getter,lombok使用.在setting中搜索Annotation processors自动编译打开.才可以使用

    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>

    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.itlike.domain.Customer">
                  SELECT * FROM `customer` WHERE cust_id  = #{cust_id}
                </select>
            </mapper>
    6.在核心配置文件当中引入Mapping
            <!--加载映射文件-->
                <mappers>
                    <mapper resource="com/myxq/domain/Customer.xml"></mapper>
                </mappers>
    7.创建工厂,执行sql语句
        

    3.    Mtbatis-快速入门-执行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.获取session -----JDBC连接
        SqlSession sqlSession = sessionFactory.openSession();
        //5.执行sql
        Customer customer = sqlSession.selectOne("queryCustomerById", 4);
        System.out.println(customer);
        //6.关闭session
        sqlSession.close();
    }
注意:SqlMappingConfig.xml必须放在src下面.
输出结果:Customer{cust_id=4, cust_name='德玛西亚', cust_profession='肉盾', cust_phone='13700997665', email='demaxiya.126.com6'}

    4.    Mybatis-快速入门-执行流程演示
第一步加载配置文件,第二步读取配置文件SqlMappingConfig.xml
第三步获取一个session工厂,创建JDBC连接.
第四步执行sql语句,关闭session.

    5.    Mybatis-整体架构分析
Mybatis核心API
1. SqlSessionFactoryBuilder
    SqlSessionFactoryBuilder用于创建SqlSessionFacoty
    SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了
    因为SqlSession是通过SqlSessionFactory创建的
    所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

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

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

Mybatis的两种配置文件,总的配置文件SqlMappingConfig.xml和下面小的Mapping.xml配置sql语句

    6.    Mybatis-封装工具类查询所有用户.
抽出一个MyBatisUtils方法

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();
    }
}

在test类里面就可以简化为
    @Test
    public void test() throws IOException{
    //直接使用MybatisUtils类创建session连接
        SqlSession sqlSession = MyBatisUtils.openSession();
        //5.执行sql
        Customer customer = sqlSession.selectOne("queryCustomerById", 4);
        System.out.println(customer);
        //6.关闭session
        sqlSession.close();
    }


在Customer.xml里面添加查询全部的sql语句
    <!--查询所有-->
    <select id="queryCustomerAll"  resultType="com.company.domain.Customer">
      SELECT * FROM `customer`
    </select>

//    查询所有用户
    @Test
    public void test2(){
        SqlSession sqlSession = MyBatisUtils.openSession();
        List<Customer> queryCustomerAll = sqlSession.selectList("queryCustomerAll");
        for (Customer customer : queryCustomerAll) {
            System.out.println(customer);
        }
        sqlSession.close();
    }

    7.    Mybatis-配置SQL打印.
在SqlMappingConfig.xml里面配置
    <!--配置SQL打印-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
#{cust_id}会替换为'?'
SELECT * FROM `customer` WHERE cust_id  = #{cust_id}
就是==> SELECT * FROM `customer` WHERE cust_id = ?     

    8.    Mybatis-- #{}与${}区别
模糊查询SQL语句
SELECT * FROM customer WHERE cust_name LIKE '%李%';
查询名字中含有李的.

重点
#{}和${}
    #{}
        表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值
        自动进行java类型和jdbc类型转换
        #{}可以有效防止sql注入
        #{}可以接收简单类型值或pojo属性值
        如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称

    ${}
        表示拼接sql串
        通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换
        ${}可以接收简单类型值或pojo属性值
        如果parameterType传输单个简单类型值,${}括号中只能是value

模糊查询的两种方法
1.使用${}拼接字符串的方式
Customer.xml
    <!--根据用户名模糊查询客户-->
    <select id="queryCustomerByName" parameterType="String" resultType="com.company.domain.Customer">
        SELECT * FROM `customer` WHERE cust_name LIKE '%${value}%';
    </select>

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

2.使用#{}占位符的方式
    <!--根据用户名模糊查询客户-->
    <select id="queryCustomerByName" parameterType="String" resultType="com.company.domain.Customer">
        SELECT * FROM `customer` WHERE cust_name LIKE #{name};
    </select>

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

 

parameterType    指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中
resultType    指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,
        则分别进行映射,并把对象放到容器List中

selectOne    查询一条记录    如果使用selectOne查询多条记录则抛出异常
selectList    可以查询一条或多条记录

    9.    Mybatis-插入操作
保存更新删除
customer.xml
    <!--添加-->
    <insert id="insertCustomer" parameterType="com.company.domain.Customer">
        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("后羿");
        customer.setCust_phone("189000999");
        customer.setCust_profession("辅助");
        sqlSession.insert("insertCustomer",customer);
        //当要改动数据库当中的记录时,执行sql时要自己提交事务
        //手动提交事务
        sqlSession.commit();
        System.out.println(customer);
        sqlSession.close();
    }


    10.    Mybatis-获取最后插入的ID
常见场景,在注册用户信息时,先注册账号和密码,然后再完善其他的信息.
在注册账号密码时,先插入一条数据,后续再更新性别地址职业等信息.
从插入界面到更新界面需要获取用户的ID.

customer.xml里添加
    <!--添加-->
    <insert id="insertCustomer" parameterType="com.company.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("1890009993");
        customer.setCust_profession("辅助");
        sqlSession.insert("insertCustomer",customer);
        //当要改动数据库当中的记录时,执行sql时要自己提交事务
        //手动提交事务
        sqlSession.commit();
        System.out.println(customer);
        System.out.println(customer.getCust_id());
        sqlSession.close();
    }

    11.    Mybatis-更新与删除操作
更新客户
customer.xml里添加
    <update id="updateCustomer" parameterType="com.company.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", 3);
        customer.setCust_name("武圣");
        sqlSession.update("updateCustomer",customer);
        sqlSession.commit();
        sqlSession.close();
    }

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

    @Test
    public void delete(){
        SqlSession sqlSession = MyBatisUtils.openSession();
        sqlSession.delete("deleteCustomer",12);
        sqlSession.commit();
        sqlSession.close();
    }

    12.    Mybatis-传统模式开发DAO
建立Dao接口
public interface CustomerDao {
    public Customer getCustomerWithId(Integer id);
    public List<Customer> getAllCustomer();
    public void addCustomer(Customer customer);
    public void upadteCustomer(Customer customer);
}
实现类Impl
public class CustomerDaoImpl implements CustomerDao {
    @Override
    public Customer getCustomerWithId(Integer id) {
        SqlSession sqlSession = MyBatisUtils.openSession();
        Customer customer = sqlSession.selectOne("queryCustomerById", 12);
        System.out.println(customer);
        sqlSession.close();
        return customer;
    }

    @Override
    public List<Customer> getAllCustomer() {
        SqlSession sqlSession = MyBatisUtils.openSession();
        List<Customer> customers = sqlSession.selectList("queryCustomerAll");
        sqlSession.close();
        return customers;

    }

    @Override
    public void addCustomer(Customer customer) {
        SqlSession sqlSession = MyBatisUtils.openSession();
        sqlSession.insert("insertCustomer",customer);
        sqlSession.commit();
        sqlSession.close();

    }

    @Override
    public void upadteCustomer(Customer customer) {
        SqlSession sqlSession = MyBatisUtils.openSession();
        sqlSession.update("updateCustomer",customer);
        sqlSession.commit();
        sqlSession.close();

    }
}

实例化查询
public class Test2 {
    @Test
    public void test(){
        CustomerDao customerDao = new CustomerDaoImpl();
        customerDao.getCustomerWithId(1);
        customerDao.getAllCustomer();
    }
}

    13.    Mybatis-Mapper动态代理规则
要求
    1.namespace必须和Mapper接口类路径一致     namespace是在Customer.xml定义的.    
    2.id必须和Mapper接口方法名一致
    3.parameterType必须和接口方法参数类型一致
    4.resultType必须和接口方法返回值类型一致

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

建立一个接口CustomerMapper.
修改Customer.xml里额namespace.
<mapper namespace="com.company.mapper.CustomerMapper">
修改接口
public interface CustomerMapper {
    //查询单条
    public Customer queryCustomerById(Integer id);
    //查询全部
    public List<Customer> queryCustomerAll();
    //模糊查询
    public List<Customer> queryCustomerByName(String name);
    //添加操作
    public void insertCustomer(Customer customer);
    //更新操作
    public void updateCustomer(Customer customer);
    //删除
    public void deleteCustomer(Customer customer);
}

    14.    Mybatis-Mapper动态代理调用
实例化实现.
查询全部.
    @Test
    public void test2(){
        SqlSession sqlSession = MyBatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        mapper.queryCustomerAll();
    }
delete操作
    @Test
    public void test2(){
        SqlSession sqlSession = MyBatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
//        mapper.queryCustomerAll();
        Customer customer = new Customer();
        customer.setCust_id(16);
        mapper.deleteCustomer(customer);
        sqlSession.commit();
        sqlSession.close();
模糊查询
    @Test
    public void test2(){
        SqlSession sqlSession = MyBatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        List<Customer> customers = mapper.queryCustomerByName("%李%");
        for (Customer customer : customers) {
            System.out.println(customer);
        }
        sqlSession.close();


    15.    Mybaits-Mapper工程创建
创建和表相同的Customer,添加getset方法.
添加SqlMappingConfig.xml方法
创建自己的MyBatisUtils工具类创建连接提供openSession方法.

添加Customer.xml
<mapper namespace="com.itlike.mapper.CustomerMapper">
    <!--查询用户 ID-->
    <select id="getCustomerWithId" parameterType="Integer" resultType="com.itlike.domain.Customer">
        select * from  `customer` where cust_id = #{id}
    </select>
</mapper>

添加CustomerMapper的接口
public interface CustomerMapper {
    public Customer getCustomerWithId(Integer id);
}

测试类
public class MyTest {
    @Test
    public void test1() {
        SqlSession sqlSession = MyBatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customerWithId = mapper.getCustomerWithId(2);
        System.out.println(customerWithId);
        sqlSession.close();
    }
}

    16.    Mybatis-Mapper传参多个普通类型与@param
1.单个参数
    可以接受基本类型,对象类型,集合类型的值。
    MyBatis可直接使用这个参数,不需要经过任何处理。

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

使用param1,param2....    或者使用arg0,arg1...
在mapper里设置
    <select id="getCustomerWithId" resultType="com.itlike.domain.Customer">
        select * from  `customer` where cust_id = #{param1} and cust_name = #{param2}
    </select>
在MyTest
    @Test
    public void test1() {
        SqlSession sqlSession = MyBatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customerWithId = mapper.getCustomerWithId(2,"李白");
        System.out.println(customerWithId);
    }

3.@param命名参数
    为参数使用@Param起一个名字,
    MyBatis就会将这些参数封装进map中,key就是我们自己指定的名字
在接口CustomerMapper里添加@Param
public interface CustomerMapper {
    public Customer getCustomerWithId(@Param("id") Integer id,@Param("name") String name);
}

在多参数时在customer.xml里可以直接定义参数名
    <!--查询用户 ID-->
    <select id="getCustomerWithId" resultType="com.itlike.domain.Customer">
        select * from  `customer` where cust_id = #{id} and cust_name = #{name}
    </select>

当使用@param时,不能再使用arg0,arg1,可以继续使用param1,param2.


    17.    Mybatis-Mapper传参Map类型和POJO类.
4.Map
    我们也可以封装多个参数为map,直接传递
添加接口CustomerMapper.xml
    public Customer getCustomerWithId(Map<String,Object> map);
MyTest
    @Test
    public void test1() {
        SqlSession sqlSession = MyBatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("id",2);
        hashMap.put("name","李白");
        Customer customerWithId = mapper.getCustomerWithId(hashMap);
        System.out.println(customerWithId);
    }
使用hashMap来进行查询
在Customer里的参数需要为id和name和hashmap相对应.

5.POJO
    当这些参数属于我们业务POJO时,我们直接传递POJO
新增接口
    public Customer getCustomerWithId(Customer customer);
修改参数的值必须和Customer字段相同
    <!--查询用户 ID-->
    <select id="getCustomerWithId" resultType="com.itlike.domain.Customer">
        select * from  `customer` where cust_id = #{cust_id} and cust_name = #{cust_name}
    </select>
测试
    @Test
    public void test1() {
        SqlSession sqlSession = MyBatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customer = new Customer();
        customer.setCust_id(2);
        customer.setCust_name("李白");
        Customer customerWithId = mapper.getCustomerWithId(customer);
        System.out.println(customerWithId);
}

    18    Mybatis-Mapper参数传递源码分析
参数传递源码分析
    会把参数给放到一个数组当中
    如果一个参数, 内部处理时,会自动把该参数范围
        
    如果是多个参数,内部会做判断
    判断是否有@param注解
        如果没有
            没有注解的话, 就直接使用arg0  arg1...为key  放到map中
            并且还会以param1和param2...为key放一份到map中
                
        如果有
            如果有注解的话, 会使用注解当中的值,替换掉默认的arg0和arg1
            使用@param中的值,做为key 放到一个map当中
            并且还会以param1和param2...为key放一份到map中
    
    

    19    Mybatis-properties配置
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
configuration(配置)
    properties(属性)
    settings(设置)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境配置)
        environment(环境变量)
            transactionManager(事务管理器)
            dataSource(数据源)
    databaseIdProvider(数据库厂商标识)
    mappers(映射器)

properties最基本的直接使用法.
    <!--定义属性及读取属性文件-->
    <properties>
        <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
    </properties>
SqlMappingConfig.xml
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
            </dataSource>

使用db.properties
新建一个db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=cqkill000
    <!--定义属性及读取属性文件-->
    <properties resource="db.properties" />

            <!-- 数据库连接池 -->
            <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>

db.properties的优先级高于属性.


    20.    Mybatis-Settings配置
settings
    这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为

    <!--配置sql打印-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--开启驼峰命名法-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。
custId --->cust_id
custName--->cust_name
前一种属于驼峰命名法,后面一种属于经典库名.使驼峰命名法可以与库名进行映射.


    21.    Mybatis-typeAliases配置
typeAliases
类型别名是为 Java 类型设置一个短的名字
    定义单个别名
在sqlmappingConfig.xml中
    <!--定义别名-->
    <typeAliases>
        <typeAlias alias="Customer" type="com.itlike.domain.Customer"/>
    </typeAliases>
在Customer.xml中修改
    <!--查询用户 ID-->
    <select id="getCustomerWithId" resultType="com.itlike.domain.Customer">
可以去掉com.itlike.domain.的前缀,直接在resultType中输入Customer
        
    批量别名定义,在
        <!--批量定义别名,别名为类名-->
        <package name="com.itlike.domain"/>

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

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

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

Environments(非重点,交spring处理)
    MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置。
    每种环境使用一个environment标签进行配置并指定唯一标识符
    可以通过environments标签中的default属性指定一个环境的标识符来快速的切换环境
    Environment子标签
        transactionManager事务管理
            Type有以下取值
            JDBC
                使用JDBC 的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围
            MANAGED
                不提交或回滚一个连接、让容器来管理事务的整个生命周期
                ManagedTransactionFactory
            自定义
                实现TransactionFactory接口 
                type=全类名/别名
        dataSource数据源
            type有以下取值
            UNPOOLED
                不使用连接池UnpooledDataSourceFactory
            POOLED
                使用连接池PooledDataSourceFactory
            JNDI
                在EJB 或应用服务器这类容器中查找指定的数据源
            自定义
                实现DataSourceFactory接口,定义数据源的获取方式
        实际开发
            实际开发中我们使用Spring管理数据源
            并进行事务控制的配置来覆盖上述配置


    23.    Mybatis-databaseIDProvider配置
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>

    <select id="getCustomerWithId" resultType="Customer" databaseId="mysql">

    24.    Mybatis- mappers配置
mappers加载映射文件
    <mapper resource="com/itlike/domain/Customer.xml"></mapper>
        使用相对于类路径的资源
            
    <mapper class="com.itlike.mapper.CustomerMapper"/>
        使用mapper接口类路径
        此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
                    
    <package name="com.itlike.mapper"/>
        指定包下的所有mapper接口
        此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
            

    25.    Mybatis-IDEA中Mybatis插件安装.
最后使用了better mybatis generator和free mybatis plugin
实现自动生成mapper.xml文件,识别insert,get,save等语句.自动生成@Param.

    26.    Mabatis-查询输出简单类型
创建一个新的工程MyBatis4.

语句一:select count(*) from T;
作用:Select count(*) from 返回的是当前表中数据的条数
语句二:select * from T;
作用:查询T表中所有的记录。

输出类型:
1.输出简单类型:
Customer
    public Integer getAccountCustomer();
CustomerMapper.xml
    <select id="getAccountCustomer" resultType="java.lang.Integer">
        select count(*) from customer;    //获取总的数据条数
    </select>
test
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        Integer accountCustomer = customerMapper.getAccountCustomer();
        System.out.println(accountCustomer);
        sqlSession.close();
    }

目录下的out文件如果不想看到就关闭show excluded files,在Analyze的下方不是下拉列表


    27    Mybatis-查询输出Map类型
Map
    第1种形式
        key:是列名  value:是列名对应的值
    示例:
Customer
    public Map<String,Object> getCustomerWithId(Integer id);
.xml
    <select id="getCustomerWithId" resultType="java.util.Map">
        select * from `customer` where cust_id=#{id};
    </select>
test
    Map<String, Object> customerWithId = customerMapper.getCustomerWithId(2);

        
    第2种形式
        Map<key,自定义对象>
            key为自己指定的我列
    示例:
Customer
    @MapKey("cust_id")    //指定key的值,自己指定的列
    public Map<Integer,Customer> getCustomer();
Customer.xml
    <select id="getCustomer" resultType="java.util.Map">
        select * from `customer`;
    </select>
test
    Map<Integer, Customer> customer = customerMapper.getCustomer();


    28.    Mybatis-查询输出resultMap类型
resultMap
    之有在写输出时使用的都是resultType
    但是resultType要求必须得要字段名称和数据库当中的名称一致时才能有值,否则为null
    如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系
    表名与domain

修改Customer的属性名在后面都添加s
@Getter@Setter@ToString
public class Customer {
    private Integer cust_ids;
    private String cust_names;
    private String cust_professions;
    private String cust_phones;
    private String email;
}
customer
    public Customer getCustomers(Integer id);
customer.xml
    <resultMap id="customerMap" type="Customer">    //指定映射,和数据库字段不同的,相同的可以不指定.
        <id column="cust_id" property="cust_ids"/>
        <result column="cust_name" property="cust_names"/>
        <result column="cust_phone" property="cust_phones"/>
        <result column="cust_profession" property="cust_professions"/>
    </resultMap>
    <select id="getCustomers" resultType="com.itlike.domain.Customer">
        select * from `customer` where cust_id=#{id};
    </select>
test
        Customer customers = customerMapper.getCustomers(2);
        System.out.println(customers);

    29    Mybatis-一对多表关系建立
表之间的关系:一对多
一个部门有多个员工,一个员工只能属于某一个部门
一个班级有多个学生,一个学生只能属于一个班级.
表之间关系键原则:
一对多:在多的一方创建一个外键,指向一的一方的主键
创建另外一个表order
含有order_id,order_name,order_num,cust_id
设置该表的外键名为cust_order,字段为cust_id参考表customer参考字段为cust_id.

    30.    Mybatis-级联属性赋值
column 是对应数据库中表的字段名称
property是对应的bean里面的属性名称
创建一个查询语句通过左外连接查询
SELECT * FROM `order` as o LEFT JOIN `customer` as c ON o.cust_id=c.cust_id;

新建一个OrderMapper,生成它的映射文件OrderMapper.xml
ordermapper
    public List<Order> getAllOrders();

ordermapper.xml
    <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_num"/>
//上半为order的数据,下面为customer的数据
        <result property="customer.cust_id" column="cust_id"/>
        <result property="customer.email" column="email"/>
        <result property="customer.cust_name" column="cust_name"/>
        <result property="customer.cust_phone" column="cust_phone"/>
        <result property="customer.cust_profession" column="cust_profession"/>
    </resultMap>
    <select id="getAllOrders" resultMap="orderMap">
        SELECT * FROM `order` as o LEFT JOIN `customer` as c ON o.cust_id=c.cust_id;
    </select>

test
    @Test
    public void test2(){
        SqlSession sqlSession = MybatisUtils.openSession();
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        List<Order> allOrders = mapper.getAllOrders();
        System.out.println(allOrders);
        sqlSession.close();
    }
          

    31.    Mybatis-association关联对象赋值
column 是对应数据库中表的字段名称
property是对应的bean里面的属性名称
修改ordermapper.xml
    <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_num"/>
//下面为修改的部分,customer的数据,不用添加customer.xxx直接写.
        <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` as c ON o.cust_id=c.cust_id;
    </select>
            
    
    32.    Mybatis-association分步查询
association分步查询步骤
第一步 先查出所有的订单
第二步 根据id查出对应客户


orderMapper
    //查询单个订单分步查询
    public Order getOrderWithId(Integer id);

customer中添加查询方法
<select id="getCustomerWithOrderId" resultType="com.itlike.domain.Customer">
        select * from customer where cust_id=#{id};

orderMapper.xml
    <resultMap id="resultMap2" type="Order">
        <id property="order_id" column="order_id"/>
        <result property="order_name" column="order_name"/>
        <result property="order_num" column="order_num"/>

//注意这里使用的select是二次查询使用的是CustomerMapper.xml的地址<mapper namespace="com.itlike.mapper.CustomerMapper">
//调用的是customer中的查询方法    
  
        <association property="customer" javaType="Customer"
                     select="com.itlike.mapper.CustomerMapper.getCustomerWithOrderId"
                     column="cust_id">
        </association>
    </resultMap>
    <select id="getOrderWithId" resultMap="resultMap2">
        SELECT *FROM `order` where order_id=#{id};
    </select>
在test中使用
    //分步查询测试
    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.openSession();
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        Order orderWithId = mapper.getOrderWithId(2);
        System.out.println(orderWithId);
        sqlSession.close();
    }


    33.    Mybatis-分步查询懒加载
分部查询懒加载:分步查询的好处就是支持懒加载
懒加载的作用
在SqlMappingConfig.xml里配置开启懒加载
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>

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


    34.    Mybatis-多对一添加操作
先添加客户,获取客户生成的id,再去添加订单
添加客户的过程
Customer中添加方法
    //保存客户
    public void insertCustomer(Customer customer);
Customer.xml
    <!--保存客户-->
    <insert id="insertCustomer" parameterType="com.itlike.domain.Customer"
            useGeneratedKeys="true"        //获取生成的key
            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>
设计添加订单的sql
order中添加接口
    //保存订单
    public void insertOrder(Order order);
order.xml
//保存订单的sql注意关联customer.cust_id
    <insert id="insertOrder" parameterType="Order">
        insert into `order`(order_name,order_num,cust_id)
        values (#{order_name},#{order_num},#{customer.cust_id});
    </insert>

在test中测试
    //多对一添加操作
    @Test
    public void test4(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);

        Order order = new Order();
        order.setOrder_name("新的订单001");
        order.setOrder_num("20000001001");

        Customer customer = new Customer();
        customer.setCust_name("新客户001");
        customer.setCust_phone("13908381234");
        customer.setEmail("OrderMail@163.com");
        customer.setCust_profession("新职业0001");
        //设置关系
        order.setCustomer(customer);
        //先添加客户,获取客户生成的id,再去添加订单
        //添加客户
        customerMapper.insertCustomer(customer);
        System.out.println(customer);
        //添加订单
        orderMapper.insertOrder(order);
        System.out.println(order);
        sqlSession.commit();
        sqlSession.close();
    }

    35.    Mybatis-一对多左连接查询操作
先在Customer的实体类中添加一个list集合来保存多个订单信息
    private List<Order> orders = new ArrayList<>();
创建一个Customer方法
    //查询所有客户
    public List<Customer> getAllCustomer();

创建.xml映射的sql语句    注意其中使用collection
    <select id="getAllCustomer" resultMap="custMap">
        SELECT * FROM `customer` as c LEFT JOIN `order`as o ON c.cust_id=o.cust_id;
    </select>
    <resultMap id="custMap" type="Customer">
        <id column="cust_id" property="cust_id"/>
        <result column="cust_name" property="cust_name"/>
        <result column="cust_phone" property="cust_phone"/>
        <result column="cust_profession" property="cust_profession"/>
        <result column="email" property="email"/>

        <collection property="orders" ofType="Order">
            <id column="order_id" property="order_id"/>
            <result column="order_name" property="order_name"/>
            <result column="order_num" property="order_num"/>
        </collection>
    </resultMap>
测试用例
    @Test
    public void test5(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        List<Customer> allCustomer = mapper.getAllCustomer();
        for (Customer customer : allCustomer) {
            System.out.println(customer);
        }
        sqlSession.close();
    }

    36.    Mybatis-一对多分步查询
需要在sqlmappingconfig核心配置文件中配置懒加载

创建customer方法
    //一对多分步查询
    public List<Customer> getAllCustomers();
创建order方法根据cust_id查询
    //根据cust_id查询订单
    public Order getOrderWithCustId(Integer id);
实现的sql语句order.xml
    <select id="getOrderWithCustId" resultType="com.itlike.domain.Order">
        select * from `order` where cust_id=#{id};
    </select>
分步查询实现的sql
    <!--分步查询-->
    <select id="getAllCustomers" resultMap="custMapp">
        select * from `customer`;
    </select>
    <resultMap id="custMapp" type="Customer">
        <id column="cust_id" property="cust_id"/>
        <result column="cust_name" property="cust_name"/>
        <result column="cust_phone" property="cust_phone"/>
        <result column="cust_profession" property="cust_profession"/>
        <result column="email" property="email"/>

        <collection property="orders" javaType="list" ofType="Order"
                    select="com.itlike.mapper.OrderMapper.getOrderWithCustId" column="cust_id">
        </collection>
    </resultMap>

test测试
    @Test
    public void test6(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        List<Customer> allCustomers = mapper.getAllCustomers();
        for (Customer allCustomer : allCustomers) {
            System.out.println(allCustomer);
        }
        sqlSession.close();
    }

分步查询和左连接查询相比,弊端在于需要发送多条sql语句,好处在于可以懒加载按需加载
如果需要一次性查询全部数据使用左连接.

    37.    Mybaits-一对多的添加操作
添加一个更新的接口在ordermapper里
    //更新关系
    public void updateCustId(@Param("orderId") Integer orderId, @Param("custId") Integer custId);
实现ordermapper.xml
    <!--更新关系-->
    <update id="updateCustId">
        update `order` set `cust_id` =#{custId} where `order_id`=#{orderId};
    </update>
修改插入insert方法,获取添加的order_id
添加参数useGeneratedKeys="true"       keyColumn="order_id"      keyProperty="order_id"

测试类
    @Test
    public void test7(){
        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("一对多添加用户订单1");
        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();
    }

    38    Mybatis-一对多的删除操作
由于customer表的cust_id是order表的外键,
所以删除时一定要先打破关系再做删除操作.
在order表中添加打破关系的方法
    //打破与customer的关系
    public void updateRelationCustomer(Integer custId);

order.xml中让order中的cust_id为null
    <!--打破customer关系-->
    <update id="updateRelationCustomer">
        update `order` set cust_id =null  where cust_id=#{custId};
    </update>

添加customer中的接口
    //删除根据用户id
    public void deleteCustomer(Integer id);
customer中的实现方法
    <!--根据id删除用户-->
    <delete id="deleteCustomer">
        delete from `customer` where cust_id=#{id};
    </delete>

测试test
    @Test
    public void testDelete(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        //一对多删除之前,要先打破关系
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        orderMapper.updateRelationCustomer(23);
        //删除操作
        customerMapper.deleteCustomer(23);
        sqlSession.commit();
        sqlSession.close();
    }

    39.    Mybatis-多对多关系表建立
一个老师可以教多个学生,一个学生可以被多个老师教
一个学生可以选择多门课程,一门课程可以被多个学生选择
一个用户可以选择多个角色,一个角色也可以被多个用户选择
多对多的建表原则:创建一个中间表,中间表至少有两个字段,分别作为外键指向多对多双方的主键

建立数据库中的表student,teacher,stu_teacher_rel.
建立idea中的实体类:
Student,Teacher.

    40.    Mybatis-多对多左连接查询
建立teachermapper接口
提供方法
    //查询老师 并且把关联的学生也查出来
    public List<Teacher> getAllTeachers();
teacherMapper.xml提供映射方法
    <!--查询老师 并且把关联的学生也查出来-->
    <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>
test测试
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.openSession();
        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> allTeachers = teacherMapper.getAllTeachers();
        for (Teacher allTeacher : allTeachers) {
            System.out.println(allTeacher);
        }
        sqlSession.close();
    }
sql语句不通,其他的和以前相同.

    41.    Mybatis-多对多分步查询
先建立接口TeacherMapper
    //查询指定老师
    public Teacher getTeacherWithId(Integer id);

TeacherMapper.xml实现
    <!--查询指定老师-->
    <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.itlike.mapper.StudentMapper.getStuByTeach"
                    column="teacher_id"/>
    </resultMap>
    <select id="getTeacherWithId" resultMap="teacherMap2">
        SELECT * FROM teacher WHERE teacher_id=#{id};
    </select>

实现com.itlike.mapper.StudentMapper.getStuByTeach接口
在studentmapper里建立接口
    //查询指定学生
    public List<Student> getStuByTeach(Integer id);

studentMapper.xml
    <!--查询指定学生-->
    <select id="getStuByTeach" resultType="com.itlike.domain.Student">
        SELECT * FROM student WHERE stu_id in(SELECT stu_id FROM stu_teacher_rel WHERE teacher_id =#{id});
    </select>

test测试
    @Test
    public void test2(){
        SqlSession sqlSession = MybatisUtils.openSession();
        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = teacherMapper.getTeacherWithId(1);
        System.out.println(teacher);
        sqlSession.close();
    }

    42.    Mybatis-多对多添加操作
保存学生接口
    //添加学生
    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 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 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>
测试类
    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.openSession();
        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        Teacher teacher = new Teacher();
        teacher.setTeacher_name("新老师");
        Student student1 = new Student();
        student1.setStu_name("苏轼");
        Student student2 = new Student();
        student2.setStu_name("白居易");
        teacher.getStudents().add(student1);
        teacher.getStudents().add(student2);
        //保存老师
        teacherMapper.insertTeacher(teacher);
        studentMapper.insertStudent(student1);
        studentMapper.insertStudent(student2);
        //插入关系表
        for (Student student : teacher.getStudents()) {
            teacherMapper.insertRelation(student.getStu_id(),teacher.getTeacher_id());
        }
        sqlSession.commit();
        sqlSession.close();
    }

    43.    Mybatis-动态sql之if标签
什么是动态sql    通过mybatis提供的各种标签方法实现动态拼接sql。
if标签需求
根据客户名和级别查询客户
存在问题
    有可能传入的名称或级别为空
    可以使用if标签来进行判断
    如果前一个条件这后,后面就会多一个and执行就会报错
示例:
customermapper
    //根据客户名称和职业查询
    public List<Customer> getCustomer(@Param("name") String name, @Param("profession") String profession);
customermapper.xml
    <select id="getCustomer" resultType="com.itlike.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>
test测试
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        List<Customer> customer = customerMapper.getCustomer("李白", null);
        for (Customer customer1 : customer) {
            System.out.println(customer1);
        }
        sqlSession.close();
    }
如果两个传入参数都为null那么会报错,因为查询的sql变成了select*from `customer` where


    44.    Mybatis-where标签
Where标签    where标签能自动生成和删除where,还能删除where后第1个and
.xml里
    <!--where标签能自动生成和删除where,还能删除where后第1个and-->
    <select id="getCustomer" resultType="com.itlike.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>
        </where>
    </select>

    45.    Mybatis-trim标签
    <!--trim标签:
       prefix:设置前缀  在第一个条件之前加一个前缀
       prefixOverrides: 条件前缀覆盖 把第一个条件之前的and变成空
       suffix: 设置后缀 在最后一个条件之后加一个后缀
       suffixOverrides: 条件后缀覆盖  把最后一个条件之后的and变成空
   -->

    <select id="getCustomer" resultType="com.itlike.domain.Customer">
        select * from `customer`
        <trim prefix="where" prefixOverrides="and">
            <if test="name != null and name !=''">
              `cust_name`=#{name}
              </if>
            <if test="profession != null and profession !=''">
              and `cust_profession`=#{profession}
            </if>
            <if test="phone != null and phone !=''">
              and `cust_phone`=#{phone}
            </if>
        </trim>
    </select>

 

    46    Mybatis-choose标签
    <!--
    choose   只要第一个条件满足,后面条件都不执行
    when
    otherwise    
    -->

    <select id="getCustomer" resultType="com.itlike.domain.Customer">
        select * from `customer`
        <where>
            <choose>
                <when test="name!=null and name!=''">
                    `cust_name`=#{name}
                </when>
                <when test="profession != null and profession!=''">
                    `cust_profession`=#{profession}
                </when>
                <otherwise>1=1</otherwise>    //永远成立
            </choose>
        </where>
    </select>

    47    Mybatis-set标签
set标签
CustomerMapper
    //更新客户
    public void updateCustomer(Customer customer);
CustomerMapper.xml
    <!--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>

test测试
    @Test
    public void test2(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customer = new Customer();
        customer.setCust_name("诸葛亮");
        customer.setCust_profession("谋士");
        customer.setCust_id(22);
        mapper.updateCustomer(customer);
        sqlSession.commit();
        sqlSession.close();
    }
                

    48.    Mybatis-foreach标签
使用integer[]的参数
customer
//     根据ID查询指定的客户 多个客户
    public List<Customer> getCustomers(Integer[] ids);
customer.xml
    <!--根据ID查询多个客户-->
    <select id="getCustomers" resultType="com.itlike.domain.Customer" parameterType="integer[]">
        select * from `customer` where `cust_id` in
        <foreach collection="array" open="(" close=")" separator="," item="ids">
            #{ids}
        </foreach>
    </select>
test
    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        List<Customer> customers = mapper.getCustomers(new Integer[]{2,3,6});
        for (Customer customer : customers) {
            System.out.println(customer);
        }
        sqlSession.close();
    }

使用List参数
//     根据ID查询指定的客户 多个客户
    public List<Customer> getCustomers(List<Integer> ids);
.xml
    <!--根据ID查询多个客户-->
    <select id="getCustomers" resultType="com.itlike.domain.Customer" parameterType="list">
        select * from `customer` where `cust_id` in
        <foreach collection="list" open="(" close=")" separator="," item="ids">
            #{ids}
        </foreach>
    </select>
test
    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(2);
        arrayList.add(5);
        List<Customer> customers = mapper.getCustomers(arrayList);
        for (Customer customer : customers) {
            System.out.println(customer);
        }
        sqlSession.close();
    }

使用一个新的类QueryVo做为参数
@Setter@Getter@ToString
public class QueryVo {
    private Integer[] ids;
}
customer
//     根据ID查询指定的客户 多个客户
    public List<Customer> getCustomers(QueryVo vo);
customer.xml
    <!--根据ID查询多个客户-->
    <select id="getCustomers" resultType="com.itlike.domain.Customer" parameterType="QueryVo">
        select * from `customer` where `cust_id` in
        <foreach collection="ids" open="(" close=")" separator="," item="abc">
            #{abc}
        </foreach>
    </select>
test
    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        QueryVo queryVo = new QueryVo();
        queryVo.setIds(new Integer[]{2,3,4});
        List<Customer> customers = mapper.getCustomers(queryVo);
        for (Customer customer : customers) {
            System.out.println(customer);
        }
        sqlSession.close();
    }

    49    Mybatis-bind标签
bind标签可以取出传入的值,重新处理,赋值给另外一个值
customermapper
//     根据Id查询,传入参数但是查询bind给的newId=2
    public Customer getCustomerWithId(@Param("id") Integer id);
.xml
    <!--bind标签可以取出传入的值,重新处理,赋值给另外一个值-->
    <select id="getCustomerWithId" resultType="Customer">
        <bind name="newId" value="2"/>
        select * from `customer` where cust_id=#{newId}
    </select>
test
    @Test
    public void test4(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customerWithId = mapper.getCustomerWithId(5);
        System.out.println(customerWithId);
        sqlSession.close();
    }

    50.    Mybatis-sql片段
在Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
    <sql id="selectID">
        select * from `customer`
    </sql>
    <select id="getCustomerWithId" resultType="Customer">
        <include refid="selectID"/> where cust_id=#{id}
    </select>

使用sql片段+choose
    <sql id="selectID">
        <choose>
            <when test="id==2">
                select cust_name from `customer`
            </when>
            <otherwise>
                select * from `customer`
            </otherwise>
        </choose>
    </sql>

<!--在include中定义的property取得时候需要使用${}-->

        <include refid="selectID">
            <property name="1k" value="2"/>
        </include>

    51    Mybatis-一级缓存session级别缓存
一级缓存
    缓存介绍
        MyBatis中使用缓存来提高其性能。
        当查询数据时, 会先从缓存中取出数据,如果缓存中没有,再到数据库当中查询
        MyBatis中的缓存分为两种:一级缓存和二级缓存
        一级缓存是sqlSession级别的,二级缓存是mapper级别的
    一级缓存
        本地缓存 (默认开启)
        在sqlSession没有关闭之前,再去查询时, 会从缓存当中取出数据,不会重新发送新的sql

    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customerWithId = customerMapper.getCustomerWithId(3);
        System.out.println(customerWithId);
        Customer customerWithId1 = customerMapper.getCustomerWithId(3);
        System.out.println(customerWithId1);
        sqlSession.close();
    }
在test中建立两个查询id为3的数据,sqlsession没有close之前,就会从一级缓存取数据,就不会发送新的sql语句.
实际上只发送了一次sql语句去请求,第二次是直接获取的缓存.

    52.    Mybatis-一级缓存失效情况
一级缓存失效
    1.如果在查询之前,执行了增\删\改 缓存就会失效
    2.手动清空缓存
    3.如果两次的查询条件不一样,缓存也会失效
    4.如果两个查询在不同的sqlsession当中

        //插入操作,会让一级缓存失效
        Customer customer = new Customer();
        customer.setCust_id(12);
        customer.setCust_name("鲁迅");
        customerMapper.insertCustomer(customer);
    //手动清空
sqlSession.clearCache();会清空缓存
    //两次查询的条件不同也会失效
比如第一次查询1,第二次查询2.
    //使用不同的sqlsession

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

    二级缓存使用步骤
        1.确保在配置文件当中开启二级缓存
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--二级缓存开关-->
        <setting name="cacheEnabled" value="true"/>
        <!--关闭一级缓存  不使用缓存-->
        <setting name="localCacheScope" value="SESSION"/>
    </settings>

        2.在对应的mapper.xml中添加cache标签
            eviction
                回收策略
            flushInterval
                刷新间隔
                默认不清空
            readOnly
                是否只读
                true
                    告诉Mybatis是只读操作,不去修改数据
                    Mybatis为了加快获取速度,会直接将缓存的引用将给用, 不安全, 速度快
                false
                    非只读,有可能修改数据
                    Mybatis会利用序列化和反序列化复制一份给你   速度慢些
            size
                可以存放多少个元素
            type
                可以用来指定自定义的缓存
        3.POJO需要实现Serializable接口
需要implements
public class Customer implements Serializable {
    private Integer cust_id;
    private String cust_name;
    private String cust_profession;
    private String cust_phone;
    private String email;
}

test测试
    @Test
    public void test2(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
        Customer customerWithId = mapper.getCustomerWithId(2);
        System.out.println(customerWithId);
        //sqlsession会话关闭时,会把一级缓存的数据,放在二级缓存中
        sqlSession.close();

        SqlSession sqlSession2 = MybatisUtils.openSession();
        CustomerMapper mapper2 = sqlSession2.getMapper(CustomerMapper.class);
        Customer customerWithId2 = mapper2.getCustomerWithId(2);
        System.out.println(customerWithId2);
        sqlSession.close();
    }
sql语句只发送一次,第二次从二级缓存中读取.sqlsession会话关闭时,会把一级缓存的数据,放在二级缓存中

    
    54.    Mybatis-二级缓存cache相关属性
注意事项
    查询的数据都会先放到一级缓存当中
    只有会话关闭,一级缓存中的数据才会转称到二级缓存中
eviction回收策略4种
LRU(默认)    最近最少使用,移除最长时间不使用的对象
FIFO    先进先出,按对象进入缓存的顺序移除对象
SOFT    软引用,移除基本垃圾回收器状态和软引用规则的对象.空间不足时移除
WEAK    弱引用,移除基本垃圾回收器状态和弱引入规则的对象.没使用时就移除

flushInterval    刷新间隔    默认不清空    单位毫秒

readOnly    是否只读
    true
        告诉Mybatis是只读操作,不去修改数据
        Mybatis为了加快获取速度,会直接将缓存的引用将给用, 不安全, 速度快
    false
        非只读,有可能修改数据
        Mybatis会利用序列化和反序列化复制一份给你   速度慢些
size    可以存放多少个元素
type    可以用来指定自定义的缓存,可以指定第三方缓存.

    55.    Mybatis-缓存相关配置
缓存相关属性
cacheEnabled    只能控制二级缓存的开关    在sqlmappingconfig的setting里设置

select中useCache    控制的也是二级缓存是否使用,在查询语句select中使用
        
增删改标签中flushCache    在insert,delete和update中使用
        一级和二级都会被清空
        增删改flushCache默认为true
        查询flushCache默认为false

sqlSession.clearCache()        只清除当前session的一级缓存
    
localCacheScope        本地缓存作用域    在sqlmappingconfig中使用,setting name=localCacheScope    value=session或者statement
            取值
                SESSION
                STATEMENT    STATEMENT可以使用它禁用缓存

缓存使用顺序
    先到二级缓存当中查找,二级有直接使用
    如果二级缓存中没有,就去找一级缓存
    如果一级缓存中也没有就去到数据库当中查询.
在哪个mapper下面使用二级缓存就需要使用cache

    56.    Mybatis-逆向工程-Gennerrator插件
MyBatis Generator
    代码生成器
    可以根据指定的表快速生成对应的映射文件,接口,以及Bean类
    支持基本的增删改查,以及QBC风格的条件查询
    但是一些复杂的表连接还是需要我们自己来去编写
添加一个genneratorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

    <!--
    targetRuntime:设置自动生成的版本
    MyBatis3:
    MyBatis3Simple:简单增删改查
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!--
           不要生成日期和备注
        -->
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"
                        userId="root"
                        password="1234">
        </jdbcConnection>

        <!--
        配置domain生成策略
        targetProject:把自动生成的domian放在哪个工程里面
        targetPackage:哪个包下

        -->
        <javaModelGenerator targetPackage="com.itlike.domain" targetProject=".\src">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!--
            配置mapper的生成策略
            targetPackage:把自动生成的mapper放在哪个工程里面
            targetProject:哪个包下
        -->
        <sqlMapGenerator targetPackage="com.itlike.mapper"  targetProject=".\src">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!--
            mapper接口生成策略
        -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.itlike.mapper"  targetProject=".\src">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

        <table tableName="customer" domainObjectName="Customer" ></table>
        <table tableName="teacher" domainObjectName="Teacher" ></table>
        <table tableName="student" domainObjectName="Student" ></table>
    </context>

</generatorConfiguration>


编写生成代码
    @Test
    public void test() throws Exception {
        //编写生成代码
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        File configFile = new File("./src/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);
    }

自动生成domain实体类,mapper接口和mapper.xml


    57.    Mybatis-逆向工程QBC条件使用
比simple生成的代码多了domain的example
比如:customerexample,studentExample,TeacherExample.


使用其中自动生成的customerExample.createCriteria()进行查询,查询邮箱有163且职业为刺客的
    @Test
    public void test2(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);

        CustomerExample customerExample = new CustomerExample();
        CustomerExample.Criteria criteria = customerExample.createCriteria();
        criteria.andEmailLike("%163%").andCustProfessionEqualTo("刺客");
/*
        CustomerExample.Criteria criteria2 = customerExample.createCriteria();
        criteria2.andCustProfessionEqualTo("刺客");
        customerExample.or(criteria2);
*/
        List<Customer> customers = mapper.selectByExample(customerExample);
        for (Customer customer : customers) {
            System.out.println(customer);
        }
    }

    58    Mybatis-分页插件
分页插件
    1.下载分页插件
        https://github.com/pagehelper/Mybatis-PageHelper/blob/master/README_zh.md
    2.配置分页插件
        配置位置在SqlMappingConfig.xml下面的typeAliases之后,environments之前.
        配置的其实是pagehelper的拦截器
            <plugins>
                <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
            </plugins>
    3.使用分页插件
        在查询之前设置分页
             Page<Object> page = PageHelper.startPage(1, 5);
        查询数据之后添加
            PageInfo<Customer> pageInfo = new PageInfo<>(customers, 5);
        属性介绍
                    System.out.println("当前页:"+pageInfo.getPageNum());
                    System.out.println("每页显示记录数:"+pageInfo.getPageSize());
                    System.out.println("总页数:"+pageInfo.getPages());
                    System.out.println("总记录数:"+pageInfo.getTotal());
                    System.out.println("是否有上一页:"+pageInfo.isHasPreviousPage());
                    System.out.println("是否有下一页:"+pageInfo.isHasNextPage());
                    System.out.println("导航页面:"+ Arrays.toString(pageInfo.getNavigatepageNums()));

测试使用
    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.openSession();
        CustomerMapper mapper = sqlSession.getMapper(CustomerMapper.class);
// 分页插件
        Page<Customer> page = PageHelper.startPage(2, 3);

        List<Customer> customers = mapper.selectAll();
//显示页码导航
        PageInfo<Customer> pageInfo = new PageInfo<>(customers, 6);

        for (Customer customer : customers) {
            System.out.println(customer);
        }
        System.out.println("当前页:"+pageInfo.getPageNum());
        System.out.println("每页显示记录数:"+pageInfo.getPageSize());
        System.out.println("总页数:"+pageInfo.getPages());
        System.out.println("总记录数:"+pageInfo.getTotal());
        System.out.println("是否有上一页:"+pageInfo.isHasPreviousPage());
        System.out.println("是否有下一页:"+pageInfo.isHasNextPage());
        System.out.println("导航页面:"+ Arrays.toString(pageInfo.getNavigatepageNums()));
        sqlSession.close();
    }

 

posted @ 2019-05-13 15:04  ricky0001  阅读(216)  评论(0编辑  收藏  举报