mybatis
1.依赖
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.14.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
在classpath下建立log4j.properties
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="on" monitorInterval="1800">
<!--    <properties>-->
<!--        <property name="LOG_HOME">/opt/logs/hafiz/log4j2Demo/logs</property>-->
<!--        <property name="ERROR_LOG_FILE_NAME">error</property>-->
<!--    </properties>-->
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p (%F:%L) - %m%n"/>
        </Console>
<!--        <RollingRandomAccessFile name="ErrorLog"-->
<!--                                 fileName="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log"-->
<!--                                 filePattern="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log.%d{yyyy-MM-dd}.gz">-->
<!--            <PatternLayout-->
<!--                    pattern="%d %-5p (%F:%L) - %m%n"/>-->
<!--            <Policies>-->
<!--                <TimeBasedTriggeringPolicy/>-->
<!--                <SizeBasedTriggeringPolicy size="100 MB"/>-->
<!--            </Policies>-->
<!--            <DefaultRolloverStrategy max="20"/>-->
<!--        </RollingRandomAccessFile>-->
    </Appenders>
    <Loggers>
        <!-- 3rdparty Loggers -->
<!--        <logger name="org.springframework.core" level="info">-->
<!--        </logger>-->
<!--        <logger name="org.springframework.beans" level="info">-->
<!--        </logger>-->
<!--        <logger name="org.springframework.context" level="info">-->
<!--        </logger>-->
<!--        <logger name="org.springframework.web" level="info">-->
<!--        </logger>-->
<!--        <logger name="com.hafiz.www.controller" level="info" includeLocation="true" additivity="false">-->
<!--            <appender-ref ref="ErrorLog"/>-->
<!--            <appender-ref ref="Console"/>-->
<!--        </logger>-->
        <root level="DEBUG" includeLocation="true">
            <appender-ref ref="Console"/>
        </root>
    </Loggers>
</Configuration>
2.测试
2.1.项目结构:

2.2.具体内容
(1)测试类:
public class MyBatisTest {
    @Test
    public void test() {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 获取sqlSession实例,能够执行已经映射的sql语句
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Employee employee = (Employee) sqlSession.selectOne("mybatis.mapper.EmpMapper.selectEmp", 1);
        System.out.println(employee);
    }
}
(2)mybatis全局配置文件:
<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="EmployeeMapper.xml"/>
    </mappers>
</configuration>
(3)xxxMapper.xml文件
<?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="mybatis.mapper.EmpMapper">
    <select id="selectEmp" resultType="mybatis.bean.Employee">
        select *
        from tbl_employee
        where id = #{id}
    </select>
</mapper>
- 程序会根据全局配置文件得到SqlSessionFactory
- 使用SqlSessionFactory工厂,获取到sqlSession对象并使用其进行增删改查,一个sqlSession就是代表和数据库的一次会话,用完即关闭
- 使用sql的唯一标志来告诉MyBatis执行哪个sql,且sql均是保存在sql映射文件中
 openSession方法中可以传参,用于标识是否自动提交,默认不是自动提交
 数据库中字段与实体类中属性名不一致时(包括实体类使用驼峰,而数据库中使用下划线致使不一致的情况),可以使用在sql中起别名的方式来避免此问题的发生
3.接口式编程(推荐)
xxxMapper.xml中namespace需要指定为对应mapper接口的全类名,且配置语句中的id应改为接口中对应的方法名
测试类:
public class MyBatisTest {
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }
    @Test
    public void test() throws IOException {
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        System.out.println(empMapper.getEmployeeById(1));
    }
}
4.MyBatis全局配置扩展
<?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>
    <!--myBatis可以使用properties来引入外部properties配置文件的内容-->
    <!--resource可以引入类路径下资源-->
    <!--url可以引入网络路径或者磁盘路径下的资源-->
    <properties resource="dbconfig.properties"></properties>
    <!--设置驼峰命名策略(实体类属性用驼峰,数据库字段用下划线)-->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!--起别名,使得写全类名的地方可以直接写类名,简化操作-->
    <typeAliases>
        <!--默认别名为类名小写-->
        <typeAlias type="mybatis.bean.Employee" alias="emp"></typeAlias>
        <!--package默认为每个包批量起别名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(类名小写,且别名不区分大小写))-->
        <package name="mybatis"/>
    </typeAliases>
    <!--可以配置多种环境-->
    <!--environment用于配置一个具体环境,且必须有transactionManager和dataSource标签-->
    <!--利用default属性更换环境-->
    <!--transactionManager的type属性有两种取值:1.JDBC(JdbcTransactionFactory.class) 2.MANAGED(ManagedTransactionFactory.class)-->
    <!--自定义事务管理器:实现TransactionFactory接口-->
    <!--dataSource有两种取值:1.UNPOOLED 2.POOLED 3.JNDI-->
    <environments default="development">
        <environment id="development">
            <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">
            <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>
    <!--支持多数据库厂商 DB_VENDOR(VendorDatabaseIdProvider.class) 作用是得到数据库厂商的标识(驱动自带的 JDBC接口中存在getDatabaseProductName),mybatis能够根据数据库厂商标识执行不同的sql-->
    <!--标识:MySQL  Orace SQL Server-->
    <databaseIdProvider type="DB_VENDOR">
        <!--为不同数据库厂商起别名-->
        <!--之后在mapper.xml中select标签的databaseId属性中配置所起的别名,用于标识该条sql在什么环境下使用-->
        <!--不同数据库环境下的一条sql,所编写的两个select标签相同,只是databaseId不同-->
        <property name="MySQL" value="mysql"/>
        <property name="Oracle" value="oracle"/>
        <property name="SQL Server" value="sqlserver"/>
    </databaseIdProvider>
    <!--将sql映射注册到全局配置中-->
    <!--注解配置文件:-->
    <!--1.resource用于指定类路径下的映射文件-->
    <!--2.url用于引用网络/磁盘路径下的映射文件-->
    <!--注册接口:-->
    <!--1.class用于引用接口(写接口全类名),使用此种方法,要求映射文件名和接口同名,且需要在一个包下,如果没有映射文件,则使用注解将sql写在接口上-->
    <mappers>
        <mapper resource="EmployeeMapper.xml"/>
    </mappers>
</configuration>
也可以使用注解配置别名(注解优先于配置文件生效):
/*使用注解配置别名*/
@Alias("emp")
public class Employee
MyBatis内置别名:

在接口上写注解:
public interface EmpMapper {
    @Select("select * from tbl_employee where id = #{id}")
    public Employee getEmployeeById(Integer id);
}
5.增删改查方法
xxxMapper.xml:
<?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="mybatis.dao.EmpMapper">
    <select id="getEmployeeById" resultType="emp">
        select *
        from tbl_employee
        where id = #{id}
    </select>
    <insert id="addEmp">
        insert into tbl_employee(last_name, gender, email)
        values (#{lastName}, #{gender}, #{email})
    </insert>
    <update id="updateEmp">
        update tbl_employee
        set last_name=#{lastName},
            gender=#{gender},
            email=#{email}
        where id = #{id}
    </update>
    <delete id="deleteEmpById">
        delete
        from tbl_employee
        where id = #{id}
    </delete>
</mapper>
测试类:
import mybatis.dao.EmpMapper;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisTest {
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }
    @Test
    public void test() {
        SqlSession sqlSession = null;
        try {
            sqlSession = getSqlSessionFactory().openSession();
            EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
            System.out.println(empMapper.getEmployeeById(1));
//            Employee employee = new Employee(null,"Jerry", "123@qq.com", "男");
//            empMapper.addEmp(employee);
//            Employee employee = new Employee(2, "Tom", "123@qq.com", "男");
//            empMapper.updateEmp(employee);
//            empMapper.deleteEmpById(2);
            sqlSession.commit();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}
MyBatis允许增删改直接定义以下返回值:1.Integer 2.Long 3.Boolean,且在update/insert/delete标签内不能写resultType
6.获取insert时的自增主键值
6.1.MySQL
MySql支持自增主键,关于自增主键的获取,可以使用statement.getGeneratedKeys()
在xxxMapper.xml文件中添加useGeneratedKeys属性,使用自增主键获取主键值策略,同时设置keyProperty属性,用于指明此值赋值给javaBean的哪个属性
    <insert id="addEmp" useGeneratedKeys="true" keyProperty="id">
        insert into tbl_employee(last_name, gender, email)
        values (#{lastName}, #{gender}, #{email})
    </insert>
测试类:
import mybatis.bean.Employee;
import mybatis.dao.EmpMapper;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisTest {
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }
    @Test
    public void test() {
        SqlSession sqlSession = null;
        try {
            sqlSession = getSqlSessionFactory().openSession();
            EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
            System.out.println(empMapper.getEmployeeById(1));
            Employee employee = new Employee(null, "Jerry", "123@qq.com", "男");
            empMapper.addEmp(employee);
            System.out.println(employee.getId());   // 返回插入词条数据时的主键值
            sqlSession.commit();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}
6.2.Oracle
Oracle不支持自增,其使用序列来模拟自增
每次插入的数据的主键是从序列中拿到的值
使用命令select * from user_sequences;可以查看所有的序列
使用select 序列名.nextval from dual;可以查询序列的值
(1)导入Oracle依赖:
        <dependency>
            <groupId>cn.easyproject</groupId>
            <artifactId>orai18n</artifactId>
            <version>12.1.0.2.0</version>
        </dependency>
        <!--解决乱码问题-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.14.1</version>
        </dependency>
(2)属性配置文件添加oracle相关连接属性:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root
orcl.driver=oracle.jdbc.OracleDriver
orcl.url=jdbc:oracle:thin:@192.168.88.135:1521:orcl
orcl.username=scott
orcl.password=scott
(3)切换配置(修改environments标签的default属性):
    <environments default="oracle">
        <environment id="mysql">
            <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="oracle">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${orcl.driver}"/>
                <property name="url" value="${orcl.url}"/>
                <property name="username" value="${orcl.username}"/>
                <property name="password" value="${orcl.password}"/>
            </dataSource>
        </environment>
    </environments>
(4)xxxMapper.xml配置文件:
其会根据连接字符串识别出当前数据库环境,查找到配置文件中相匹配的sql语句
    <insert id="addEmp" useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
        insert into tbl_employee(last_name, gender, email)
        values (#{lastName}, #{gender}, #{email})
    </insert>
    <insert id="addEmp" databaseId="oracle">
        /*BEFORE表示在sql执行之前调用 resultType表示查询数据的类型 keyProperty表示查询出的值赋给javaBean的哪个类型*/
        <selectKey keyProperty="id" order="BEFORE" resultType="int">
            select emp_seq.nextval from dual
        </selectKey>
        insert into emp(empno, ename)
        values (#{id}, #{lastName})
    </insert>
(5)测试类:
import mybatis.bean.Employee;
import mybatis.dao.EmpMapper;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisTest {
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }
    @Test
    public void test() {
        SqlSession sqlSession = null;
        try {
            sqlSession = getSqlSessionFactory().openSession();
            EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
            Employee employee = new Employee(null, "Jerry", "123@qq.com", "男");
            empMapper.addEmp(employee);
            sqlSession.commit();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}
7.MyBatis参数处理
- 使用单个参数,MyBatis不会做特殊处理,使用#{参数名}即可取出参数值,因为只有一个参数,参数名可以任意起,无需和形参名称一致
- 使用多个参数,参数会被封装成一个Map(key为param1到paramN或者arg0到argM,value为传入的参数值),因此需要使用类似#{arg0}或者#{param1}的方式获取参数值
  
- 使用多个参数时,也可以在接口方法参数上使用@param设置参数名(即使用命名参数的方式),如:public Employee getEmployeeByIdAndName(@Param("id") Integer id, @Param("lastName") String lastName);,此时sql语句中直接使用#{id}、#{lastName}即可获取参数值
- 如果多个参数是业务逻辑的数据模型的属性,则参数可直接使用POJO类型,使用#{类型属性名}即可获取参数值
- 如果多个参数没有POJO类型相匹配,则参数可使用Map,利用#{Map中属性值}即可获取参数值
- 如果多个参数虽然不是业务模型中数据,但是要经常使用,推荐编写一个TO(Transfer Object,数据传输对象),如class Page{int index;int size;}
7.1.实例
(1)public Employee getEmployeeByIdAndName(@Param("id") Integer id, String lastName),取值id=>#{id/param1}、lastName=>#{param2}
(2)public Employee getEmployeeByIdAndName(@Param("id") Integer id, @Param("e") Employee e),取值id=>#{param1}、lastName=>#{param2.lastName/e.lastName}
如果是Collection(List/Set)类型或者数组,也会特殊处理,也是把传入的list或者数组封装在map中,其中key为collection,如果是List,key也可以为list,如果是数组,则key为array
(3)public Employee getEmployees(List<Integer> ids),取出第一个id的值#{collection[0]}或者#{list[0]}
8.#{}与${}区别
二者均可以获取Map或者POJO中的值,但是#{}是以预编译的形式,将参数设置到sql语句中,类似原生JDBC使用PreparedStatement,能够防止sql注入,而${}是将取出的值直接拼装在sql语句中,存在安全问题
原生JDBC不支持占位符的地方就可以使用${}进行取值
大多情况下取参数的值都应该使用#{},但是对于分表操作(如按照年份分表拆分)select * from ${表名}
8.1.#{}丰富用法
参数可以指定特殊的数据类型,如#{property,javaType=int,jdbcType=NUMERIC}
(1)jdbcType通常需要在某种特定情况下被设置:
在数据为null时,有些数据库不能识别mybatis对null的默认处理,如Oracle在新增数据时传入null

错误原因:MyBatis对所有的null映射的都是JDBC OTHER类型,Oracle不能正确处理
- 解决方式一:设置JdbcType为null
    <insert id="addEmp" databaseId="oracle">
        /*BEFORE表示在sql执行之前调用 resultType表示查询数据的类型 keyProperty表示查询出的值赋给javaBean的哪个类型*/
        <selectKey keyProperty="id" order="BEFORE" resultType="int">
            select emp_seq.nextval from dual
        </selectKey>
        insert into emp(empno, ename)
        values (#{id}, #{lastName,jdbcType=NULL})
    </insert>
- 解决方式二:
 在全局配置文件中进行修改:
    <settings>
        <setting name="jdbcTypeForNull" value="NULL"/>
    </settings>
9.select标签
9.1.resultType
(1)如果返回list,则resultType写集合内的元素类型,如:
    <select id="getEmployeeList" resultType="emp">
        select *
        from tbl_employee
    </select>
(2)如果返回标识为一个对象的Map(即Map对应一个实体对象),key为列名,值为对应的值,resultType为map
    <select id="getEmployeeById" resultType="map">
        select *
        from tbl_employee
        where id = #{id}
    </select>
(3)如果返回多条记录封装成的Map,如Map<String,Employee>
Mapper接口:
public interface EmpMapper {
    // 标识map的key为id属性
    @MapKey("id")
    public Map<String, Employee> getEmployeeList();
}
配置文件:
    <select id="getEmployeeList" resultType="emp">
        select *
        from tbl_employee
    </select>
9.2.resultMap
此属性用于自定义结果集
9.2.1.定义普通对象映射规则:
<mapper namespace="mybatis.dao.EmployeeMapperPlus">
    <select id="getEmpById" resultMap="myEmp">
        select *
        from tbl_employee
        where id = #{id}
    </select>
    <!--自定义javaBean的封装规则-->
    <!--type为自定义的Java类型 id自定义,唯一id便于引用-->
    <!--id标签用于定义主键,底层有优化 result标签用于定义普通属性-->
    <resultMap id="myEmp" type="emp">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>
    </resultMap>
</mapper>
9.2.2.级联查询
(1)使用级联属性
    <select id="getEmployeeAndDept" resultMap="myDifEmp">
        select e.id id, e.last_name last_name, e.gender gender, d.id did, d.dept_name dept_name
        from tbl_employee e
                 left join tbl_dept d on e.dept_id = d.id
        where e.id = #{id}
    </select>
    <!--联合查询,使用级联属性封装-->
    <resultMap id="myDifEmp" type="emp">
        <id property="id" column="id"></id>
        <result property="lastName" column="last_name"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>
        <result column="did" property="dept.id"></result>
        <result column="dept_name" property="dept.deptName"></result>
    </resultMap>
(2)使用association标签
    <select id="getEmployeeAndDept" resultMap="myDifEmp">
        select e.id id, e.last_name last_name, e.gender gender, d.id did, d.dept_name dept_name
        from tbl_employee e
                 left join tbl_dept d on e.dept_id = d.id
        where e.id = #{id}
    </select>
    <resultMap id="myDifEmp" type="emp">
        <id property="id" column="id"></id>
        <result property="lastName" column="last_name"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>
        <!--association标签可用于在指定联合的javaBean对象 property属性用于指定哪个属性是联合的对象 javaType属性指定属性对象的类型(此处不可省)-->
        <association property="dept" javaType="dept">
            <id property="id" column="did"></id>
            <result property="deptName" column="dept_name"></result>
        </association>
    </resultMap>
(3)使用association进行分步查询
    <select id="getEmpByIdStep" resultMap="MyEmpByStep">
        select *
        from tbl_employee
        where id = #{id}
    </select>
    <resultMap id="MyEmpByStep" type="emp">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>
        <!--select属性表明当前属性是调用select指定的方法查出的结果 column指指定将哪一列的值传给这个方法-->
        <!--流程:使用select指定的方法(传入column指定的此列参数的值),并封装给对应的property属性-->
        <association property="dept" select="mybatis.dao.DepartmentMapper.getDepartmentById" column="dept_id">
            <id column="id" property="id"></id>
            <result column="dept_name" property="deptName"></result>
        </association>
    </resultMap>
(4)延迟加载(在分布查询基础上)
可以在分布查询的基础上,使用延迟加载,如果部门信息在使用时再去查询,则能够有效节省资源
在全局配置上配置两个属性,即可开启此功能
    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
测试代码:(只获取员工相关属性信息时,不会查询部门表)
            EmployeeMapperPlus employeeMapperPlus = sqlSession.getMapper(EmployeeMapperPlus.class);
            Employee employee = employeeMapperPlus.getEmpByIdStep(1);
            System.out.println(employee.getLastName());

(5)collection关联集合
    <select id="getDepartmentByIdPlus" resultMap="MyDept">
        select d.id did, d.dept_name dept_name, e.id eid, e.last_name last_name, e.email email, e.gender gender
        from tbl_dept d
                 left join tbl_employee e
                           on d.id = e.dept_id
        where d.id = #{id}
    </select>
    <resultMap id="MyDept" type="dept">
        <id column="did" property="id"></id>
        <result column="dept_name" property="deptName"></result>
        <!--ofType指定集合内元素类型-->
        <collection property="emps" ofType="emp">
            <id property="id" column="id"></id>
            <result property="lastName" column="last_name"></result>
            <result column="gender" property="gender"></result>
            <result column="email" property="email"></result>
        </collection>
    </resultMap>
(6)collection关联集合分步查询
    <select id="getDepartmentByIdStep" resultMap="MyDeptMap">
        select *
        from tbl_dept
        where id = #{id}
    </select>
    <resultMap id="MyDeptMap" type="dept">
        <id column="did" property="id"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps" ofType="emp" select="mybatis.dao.EmployeeMapperPlus.getEmpByDeptId" column="id">
            <id column="id" property="id"></id>
            <result column="last_name" property="lastName"></result>
            <result column="gender" property="gender"></result>
            <result column="email" property="email"></result>
        </collection>
    </resultMap>
如果要传递多列值,则可以将多列值封装成map,如column={key=columnName1,key=columnName2}的方式
        <collection property="emps" ofType="emp" select="mybatis.dao.EmployeeMapperPlus.getEmpByDeptId" column="{id=id}">
            <id column="id" property="id"></id>
            <result column="last_name" property="lastName"></result>
            <result column="gender" property="gender"></result>
            <result column="email" property="email"></result>
        </collection>
collection标签中存在fetchType属性,其可以取两个值lazy(延迟)与eager(立即),表示是否使用延迟加载,可以在此设置为eager以禁用全局的延迟加载
(7)collection关联集合分步查询
    <resultMap id="empDis" type="emp">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>
        <!--MyBatis可以使用鉴别器discriminator判断某列的值,之后根据某列的值改变封装行为-->
        <!--javaType为列值对应的java类型 column指定判断的列名-->
        <discriminator javaType="string" column="gender">
            <case value="0" resultType="emp">
                <association property="dept" select="mybatis.dao.DepartmentMapper.getDepartmentById" column="dept_id">
                    <id column="id" property="id"></id>
                    <result column="dept_name" property="deptName"></result>
                </association>
            </case>
            <!--注意此处resultType/resultMap不能省-->
            <case value="1" resultType="emp">
                <id column="id" property="id"></id>
                <result column="last_name" property="lastName"></result>
                <result column="gender" property="gender"></result>
                <result column="last_name" property="email"></result>
            </case>
        </discriminator>
    </resultMap>
10.动态SQL
    <select id="getEmpsByConditionIf" resultType="emp">
        select *
        from tbl_employee
        <where>
            /*test中使用OGNL表达式*/
            <if test="id!=null">
                id=#{id}
            </if>
            /*遇见特殊符号写转义字符  如&写成& "写成"*/
            <if test="lastName!=null or lastName !=''">
                and last_name like #{lastName}
            </if>
            <if test="email!=null or email.trim() != ''">
                and email = #{email}
            </if>
            /*OGNL会自动进行字符串与数字的转换判断*/
            <if test="gender==0 or gender==1">
                and gender = #{gender}
            </if>
        </where>
    </select>
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号