文章目录
一、Mybatis概述
①Mybatis特点
- mybatis它是一个orm框架(对象关系映射)
- 特点:自己手动写sql语句,性能好控制
- 开发效率比jdbc高,执行效率比JPA快
②mybatis的三大核心对象
- SqlSessionFactoryBuilder 主要是用来创建SqlSessionFactory的
- SqlSessionFactory 整个应用对象中只有1个对象,生命周期:随tomcat启动而创建,tomcat关闭而销毁,线程安全的
- SqlSession 每个线程都应该拿到一个SqlSession,多个线程不能共享,线程不安全的
二、Mybatis实现基础CRUD
①导入jar包
首先创建一个java普通项目,创建lib文件夹,导入以下包
mybatis-3.2.1.jar是mybatis的核心包
操作mysql数据库需要mysql-connector-java-5.1.26-bin.jar包
包导入后,右键Add as Library与项目关连起来
②为mybatis创建配置文件
首先创建一个resources文件夹,记得右键选择Mark Directory as 将该文件夹设为resource root
创建mybatis-config.xml配置文件
- 到官方API找到配置文件的头拷贝过来(也可百度)
- 配置连接数据库的环境,包括:
- 配置事务类型
- 创建并引入jdbc.properties文件,配置连接池对象(driver,url,username,password)
jdbc.properties文件
createDatabaseIfNotExist=true表示不存在该数据库就创建
driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///mybatis?createDatabaseIfNotExist=true
username=root
password=123456
mybatis-config.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>
<!--引入jdbc.properties文件-->
<properties resource="jdbc.properties"/>
<!--配置连接数据库的环境 -->
<environments default="mysql">
<!--给环境取个别名-->
<environment id="mysql">
<!--配置事务类型 JDBC:支持jdbc提交和回滚-->
<transactionManager type="JDBC"/>
<!--配置连接池对象配置-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
③创建项目层级结构
domain
创建Product实体类
public class Product {
private Long id;
private String productName;
private Long dir_id;
private Double salePrice;
private String supplier;
private String brand;
private Double cutoff;
private Double costPrice;
//getter,setter.toString...
}
dao层
创建IProductDao接口
public interface IProductDao {
void save(Product product);
void update(Product product);
void delete(Long id);
List<Product> selectAll() throws IOException;
Product selectById(Long id);
}
创建实现类ProductDaoImpl
- 实现crud的核心对象是SqlSession
- 为获取SqlSession对象,抽取工具类MybatisUtills
- mybatis事务默认开启的,除了查询都必须提交事务
MybatisUtils 工具类
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
static {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
System.out.println("解析xml失败!!!");
}
}
public static SqlSession openSession() throws Exception {
if (sqlSessionFactory == null) {
throw new Exception("xml解析异常!!");
}
return sqlSessionFactory.openSession();
}
}
ProductDaoImpl实现类
public class ProductDaoImpl implements IProductDao {
@Override
public void save(Product product) {
SqlSession sqlSession = null;
try {
//获取sqlSession对象
sqlSession = MybatisUtils.openSession();
String statement = "com.luo.mybatis._01hello.dao.IProductDao.save";
//添加数据
sqlSession.insert(statement,product);
//提交事务
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
//回滚事务
if (sqlSession != null){
sqlSession.rollback();
}
}finally {
//关闭资源
if (sqlSession != null){
sqlSession.close();
}
}
}
@Override
public void update(Product product) {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtils.openSession();
String statement = "com.luo.mybatis._01hello.dao.IProductDao.update";
sqlSession.update(statement,product);
//事务默认是开启的 但是需要提交
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
if (sqlSession != null){
//事务回滚
sqlSession.rollback();
}
}finally {
if (sqlSession != null){
sqlSession.close();
}
}
}
@Override
public void delete(Long id) {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtils.openSession();
String statement = "com.luo.mybatis._01hello.dao.IProductDao.delete";
sqlSession.delete(statement,id);
//事务默认是开启的 但是需要提交
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
if (sqlSession != null){
//事务回滚
sqlSession.rollback();
}
}finally {
if (sqlSession != null){
sqlSession.close();
}
}
}
@Override
public List<Product> selectAll() throws IOException {
//获取SqlSession 就相当于jpa的EntityManager
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtils.openSession();
//statement 定位mybatis我要去查询哪条sql语句(namespace+id)
String statement = "com.luo.mybatis._01hello.dao.IProductDao.selectAll";
//查询
List<Product> products = sqlSession.selectList(statement);
//关闭资源
return products;
} catch (Exception e) {
e.printStackTrace();
}finally {
if (sqlSession != null){
sqlSession.close();
}
}
return null;
}
/*
@Override
public List<Product> selectAll() throws IOException {
//将核心配置文件转成io流
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//获取SqlSessionFactory对象 就相当于jpa的EntityManagerFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession 就相当于jpa的EntityManager
SqlSession sqlSession = factory.openSession();
//statement 定位mybatis我要去查询哪条sql语句(namespace+id)
String statement = "com.luo.mybatis._01hello.dao.IProductDao.selectAll";
//查询
List<Product> products = sqlSession.selectList(statement);
//关闭资源
return products;
}
*/
@Override
public Product selectById(Long id) {
SqlSession sqlSession = null;
try {
//获取SQLSession
sqlSession = MybatisUtils.openSession();
//定位mybatis要查哪条语句
String statement = "com.luo.mybatis._01hello.dao.IProductDao.selectById";
//查询数据
Product product = sqlSession.selectOne(statement,id);
return product;
} catch (Exception e) {
e.printStackTrace();
}finally {
if (sqlSession != null){
sqlSession.close();
}
}
return null;
}
}
ProductDaoImpl.xml配置文件
创建ProductDaoImpl.xml配置文件
在mybatis-config.xml中映射ProductDaoImpl.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>
<!--maper映射文件-->
<mappers>
<mapper resource="com/luo/mybatis/_01hello/dao/impl/ProductDaoImpl.xml"/>
<mapper resource="com/luo/mybatis/_02mapper/mapper/EmployeeMapper.xml"/>
</mappers>
</configuration>
常见错误:
1.代表你的sql映射文件没有关联
2.代表捏statement写错了
ProductDaoImpl.xml配置
配置细节:
- 保存对象返回主键id useGeneratedKeys=“true”
- keyColumn=“id” 把数据库id这列对应的值 封装到keyProperty对应的属性中
- keyProperty=“id”
- 给类型的全限定名取别名
- 数据库中列名和domain中属性名不一致时,需要配置自定义映射规则
- 查询必须返回resultType或者resultMap
- 使用mybatis的时候,参数类型是可以不写的
<?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">
<!--映射命名空间 一般都是写dao接口的全限定名-->
<mapper namespace="com.luo.mybatis._01hello.dao.IProductDao">
<!--
配置自定义映射规则
id=""自定义映射规则的别名
type 最终转为指定的类型
-->
<resultMap id="productResultMap" type="Product">
<!--主键映射使用id-->
<id column="id" property="sid"/>
<!--普通属性映射使用result-->
<result column="dir_id" property="dirId"/>
</resultMap>
<!--
id:给查询sql语句取一个别名(必须独一无二)
resultType:返回的结果值类型
-->
<!--
数据库中列名和domain中属性名不一致时,需要配置自定义映射规则
查询必须返回resultType或者resultMap
-->
<select id="selectAll" resultMap="productResultMap">
SELECT * FROM product
</select>
<select id="selectById" parameterType="long" resultType="Product">
SELECT * FROM product WHERE id=#{id}
</select>
<delete id="delete" parameterType="long">
DELETE FROM product WHERE id=#{id}
</delete>
<update id="update" parameterType="Product">
UPDATE product SET productName=#{productName},dir_id=#{dir_id},salePrice=#{salePrice},supplier=#{supplier},
brand=#{brand},cutoff=#{cutoff},costPrice=#{costPrice} WHERE id=#{id}
</update>
<!--
useGeneratedKeys="true":表示要返回主键id
keyColumn="id" 把数据库id这列对应的值 封装到keyProperty对应的属性中
keyProperty="id"
-->
<insert id="save" parameterType="Product" useGeneratedKeys="true"
keyColumn="id" keyProperty="id">
INSERT INTO product (productName,dir_id,salePrice,supplier,brand,cutoff,costPrice)
VALUES (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
</mapper>
ProductDaoTest测试代码
public class ProductDaoTest {
private ProductDaoImpl productDaoImpl = new ProductDaoImpl();
@org.junit.Test
public void save() {
Product product = new Product();
product.setProductName("利奥波德键盘");
product.setBrand("利奥波德");
product.setSalePrice(1200.0);
product.setCutoff(0.88);
product.setCostPrice(800.0);
product.setSupplier("利奥波德");
productDaoImpl.save(product);
}
@org.junit.Test
public void update() {
Product product = productDaoImpl.selectById(2L);
product.setProductName("你被修改了");
product.setBrand("杂牌");
productDaoImpl.update(product);
}
@org.junit.Test
public void delete() {
productDaoImpl.delete(1L);
}
@org.junit.Test
public void selectAll() throws IOException {
List<Product> products = productDaoImpl.selectAll();
for (Product product:products){
System.out.println(product);
}
}
@org.junit.Test
public void selectById() {
Product product = productDaoImpl.selectById(1L);
System.out.println(product);
}
}
三、Mybatis高级查询
创建以下层级结构
①映射器
Mapper映射器(相当于dao层,不用创建实现类)
public interface EmployeeMapper {
/*
* 根据条件查询
* */
List<Employee> selectByQuery(EmployeeQuery query);
List<Employee> selectAll();
Long selectCountByQuery(EmployeeQuery query);
/*
* 批量删除(根据数组)
* */
void batchDelete(Long[] arr);
/*
* 批量删除(根据集合)
* */
void batchDelete2(List<Employee> employees);
/*
* 批量插入
* */
void batchSave(List<Employee> employees);
}
创建EmployeeQuery查询类
public class EmployeeQuery {
private String name;
private Boolean sex;
//最大年龄
private Integer maxAge;
//最小年龄
private Integer minAge;
//getter,setter...
}
②EmployeeMapper.xml文件
将EmployeeMapper.xml映射到mybatis-config.xml中
<!--maper映射文件-->
<mappers>
<mapper resource="com/luo/mybatis/_02mapper/mapper/EmployeeMapper.xml"/>
</mappers>
EmployeeMapper.xml配置
- 抽取公共sql语句只能抽sql语句的where条件和sql查询的列部分
- 使用映射器,映射命名空间(namespace)必须写dao接口的全限定名
- 写sql语句的标签id必须和对应方法名相同
- 小于符号在配置文件中属于特殊符号,进行特殊处理<![CDATA[AND age<=#{maxAge}]]>
<?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">
<!--映射命名空间 必须写dao接口的全限定名-->
<mapper namespace="com.luo.mybatis._02mapper.mapper.EmployeeMapper">
<!--
抽取公共sql语句
能抽sql语句哪些部分呢?
1.where条件
2.sql查询的列
-->
<sql id="whereSql">
<where>
<if test="name!=null and name!=''">
AND name LIKE CONCAT("%",#{name},"%")
</if>
<if test="sex!=null">
AND sex=#{sex}
</if>
<if test="maxAge!=null">
<![CDATA[AND age<=#{maxAge}]]>
</if>
<if test="minAge!=null">
AND age>=#{minAge}
</if>
</where>
</sql>
<sql id="columnSql">
id,name,age,sex
</sql>
<!--
根据查询对象高级查询
-->
<select id="selectByQuery" parameterType="EmployeeQuery" resultType="Employee">
SELECT <include refid="columnSql"/> FROM t_employee
<include refid="whereSql"/>
</select>
<select id="selectAll" resultType="Employee">
SELECT <include refid="columnSql"/> FROM t_employee
</select>
<!--
查询总数
-->
<select id="selectCountByQuery" parameterType="EmployeeQuery" resultType="long">
SELECT COUNT(*) FROM t_employee
<include refid="whereSql"/>
</select>
<!--
批量删除:
可以通过数组和集合两种方式批量删除
-->
<delete id="batchDelete" parameterType="long[]">
DELETE FROM t_employee
WHERE id IN
<!--
open:开始的位置
item:每次迭代的值的别名
separator:中间以什么分隔
close:结束位置
-->
<foreach collection="array" open="(" item="x" separator="," close=")">
#{x}
</foreach>
</delete>
<delete id="batchDelete2" parameterType="list">
DELETE FROM t_employee
WHERE id IN
<!--
-->
<foreach collection="list" open="(" item="x" separator="," close=")">
#{x.id}
</foreach>
</delete>
<insert id="batchSave" parameterType="list">
INSERT INTO t_employee (name,age,sex) VALUES
<foreach collection="list" item="x" separator=",">
(#{x.name},#{x.age},#{x.sex})
</foreach>
</insert>
③批量删除和批量添加
两种方式:分为数组和list集合方式
批量删除数组方式
<delete id="batchDelete" parameterType="long[]">
DELETE FROM t_employee
WHERE id IN
<!--
open:开始的位置
item:每次迭代的值的别名
separator:中间以什么分隔
close:结束位置
-->
<foreach collection="array" open="(" item="x" separator="," close=")">
#{x}
</foreach>
</delete>
批量删除list集合方式
<delete id="batchDelete2" parameterType="list">
DELETE FROM t_employee
WHERE id IN
<foreach collection="list" open="(" item="x" separator="," close=")">
#{x.id}
</foreach>
</delete>
批量添加list方式
<insert id="batchSave" parameterType="list">
INSERT INTO t_employee (name,age,sex) VALUES
<foreach collection="list" item="x" separator=",">
(#{x.name},#{x.age},#{x.sex})
</foreach>
</insert>
四、log4j日志
导包:
log4j常见的日志等级 :trace<debug<info<warn<error
日志配置文件必须为:log4j.properties
###全局 配置根
##log4j常见的日志等级: trace<debug<info<warn<error
log4j.rootLogger = ERROR,console
##输出局部的日志信息 打印的日志等级要大于或者等于trace等级
log4j.logger.cn.itsource=trace
##打印的日志规则 日志信息打印在控制台里面
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
##你打印的日志是有一定格式的
log4j.appender.console.layout = org.apache.log4j.PatternLayout
##讲解详细布局规则
log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%n
五、动态修改数据
当我们直接使用以前那种sql语句进行修改数据,会有数据丢失
需要通过使用set和if标签,消除数据丢失问题
<update id="update">
<!--
使用set和if标签,消除数据丢失问题
-->
UPDATE t_student
<set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="age!=null">
age=#{age},
</if>
<if test="email!=null and email!=''">
email=#{email},
</if>
<if test="sex!=null">
sex=#{sex},
</if>
</set>
WHERE id=#{id}
</update>
六、#{}和${}的区别(面试题)
#{}与${}符号的区别:
共同点: #和$都是用来取值的
参数传递普通类型(8大基本数据类型8大包装类。再加一个String)
区别:
1.#它可以取任意类型的参数
$只能取对象中的值,不能取普通类型的值
2. #取值可以有效防止sql注入 ,$符号取值它是sql拼接,不能有效防止sql注入
3. #取值让sql语句支持预编译的功能,而$符号是不支持的,所以在性能上来说#取值性能要高于$符号
4. 使用#一般是用来取值的,而$符号一般用于动态排序
例:
<!--通过id查询(Long类型)-->
<select id="selectById" resultType="Student">
SELECT * FROM t_student WHERE id=#{id}
</select>
<!--通过Student对象查询-->
<select id="selectByObj" resultType="Student">
SELECT * FROM t_student WHERE id=${id}
</select>
<!--通过查询对象查询-->
<select id="selectAllByQuery" resultType="Student">
SELECT * FROM t_student
<if test="orderByName!=null and orderByName!=''">
ORDER BY ${orderByName} ${orderByType}
</if>
</select>
七、配置多对一
以往配置多对一和一对多都是通过关联外键的方式,
但是这次使用mybatis我们不使用外键
多对一和一对多都有两种方式,两种方式都需要配置自定义映射规则resultMap
- 连表查询方式
- 子查询方式
多个员工对应一个部门
- 员工(多方)
- 部门(一方)
①准备domain
Employee类
public class Employee {
private Long id;
private String name;
private Integer age;
//多个员工对应一个部门
private Dept dept;
//getter,setter
}
Dept类
public class Dept {
private Long id;
private String name;
//getter,setter
}
②准备mapper和mapperxml
EmployeeMapper
public interface EmployeeMapper {
void save(Employee employee);
//连表查询方式
List<Employee> selectAll();
//子查询方式
List<Employee> selectAll2();
}
EmployeeMapper.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="com.luo.mybatis._02many2one.mapper.EmployeeMapper">
<resultMap id="employeeResultMap" type="Employee">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<!--
property="dept" 映射Employee中的dept属性
javaType="cn.itsource._02many2one.domain.Dept dept属性对应的类型
注意:当你使用了association映射之后,默认映射规则失效
-->
<association property="dept" javaType="Dept">
<id property="id" column="did"/>
<result property="name" column="dname"/>
</association>
</resultMap>
<select id="selectAll" resultMap="employeeResultMap">
SELECT e.id,e.name,e.age,d.id did,d.name dname FROM t_employee e
JOIN t_dept d
ON e.dept_id=d.id
</select>
<resultMap id="employeeResultMap2" type="Employee">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<!--
关联对象,用association
通过表中dept_id列的id,通过DeptMapper映射器的selectById方法查询出部门信息,封装到dept属性中
-->
<association property="dept" column="dept_id"
select="com.luo.mybatis._02many2one.mapper.DeptMapper.selectById"/>
</resultMap>
<select id="selectAll2" resultMap="employeeResultMap2">
SELECT * FROM t_employee
</select>
<insert id="save" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO t_employee (name,age,dept_id) VALUES (#{name},#{age},#{dept.id})
</insert>
</mapper>
DeptMapper
public interface DeptMapper {
void save(Dept dept);
Dept selectById(Long id);
}
DeptMapper.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="com.luo.mybatis._02many2one.mapper.DeptMapper">
<select id="selectById" resultType="Dept">
SELECT * FROM t_dept WHERE id=#{id}
</select>
<insert id="save" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO t_dept (name) VALUES (#{name})
</insert>
</mapper>
测试代码
public class EmployeeMapperTest {
@Test
public void testSave() throws Exception {
SqlSession sqlSession = MybatisUtils.openSession();
//获取员工映射器
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
//获取部门映射器
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
//先保存一方(部门),后保存多方(员工)
Dept dept = new Dept();
dept.setName("测试部");
//保存一方
deptMapper.save(dept);
Employee e1 = new Employee();
e1.setName("古二");
e1.setAge(30);
e1.setDept(dept);
Employee e2 = new Employee();
e2.setName("君君");
e2.setAge(55);
e2.setDept(dept);
//保存多方
employeeMapper.save(e1);
employeeMapper.save(e2);
//提交事务
sqlSession.commit();
}
/*
* 连接查询方式
* */
@Test
public void testSelectAll() throws Exception{
SqlSession sqlSession = MybatisUtils.openSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> employees = employeeMapper.selectAll();
for (Employee employee : employees) {
System.out.println(employee);
}
}
/*
* 子查询方式
* */
@Test
public void testSelectAll2() throws Exception{
SqlSession sqlSession = MybatisUtils.openSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> employees = employeeMapper.selectAll2();
for (Employee employee : employees) {
System.out.println(employee);
}
}
}
八、配置一对多
连表查询需要排序,不然有bug
一个部门对应多个员工
- 员工(多方)
- 部门(一方)
①准备domain
Employee类
public class Employee {
private Long id;
private String name;
private Integer age;
//getter,setter
}
Dept类
public class Dept {
private Long id;
private String name;
//一个部门对应多个员工(一对多)
List<Employee> employees = new ArrayList<Employee>();
//getter,setter
}
②准备mapper和mapperxml
EmployeeMapper
public interface EmployeeMapper {
/**
* 保存员工
* @param employee 员工对象
* @param deptId 部门id
*/
void save(@Param("e") Employee employee,@Param("deptId") Long deptId);
//根据部门id查询员工
Employee selectByDeptId(Long deptId);
}
EmployeeMapper.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="com.luo.mybatis._03one2many.mapper.EmployeeMapper">
<insert id="save">
INSERT INTO t_employee (name,age,dept_id) VALUES (#{e.name},#{e.age},#{deptId})
</insert>
<select id="selectByDeptId" resultType="Employee2">
SELECT * FROM t_employee WHERE dept_id=#{deptId}
</select>
</mapper>
DeptMapper
public interface DeptMapper {
void save(Dept dept);
//通过连表查询
List<Dept> selectAll();
//通过子查询
List<Dept> selectAll2();
}
DeptMapper.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="com.luo.mybatis._03one2many.mapper.DeptMapper">
<insert id="save" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
INSERT INTO t_dept (name) VALUES (#{name})
</insert>
<!--自定义映射规则-->
<resultMap id="deptResultMap" type="Dept2">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--
集合使用collection
-->
<collection property="employees" ofType="Employee2">
<id column="eid" property="id"/>
<result column="ename" property="name"/>
<result column="eage" property="age"/>
</collection>
</resultMap>
<select id="selectAll" resultMap="deptResultMap">
SELECT d.id,d.name,e.id eid,e.name ename,e.age eage FROM t_dept d
JOIN t_employee e
ON d.id=e.dept_id
ORDER BY d.id
</select>
<resultMap id="deptResultMap2" type="Dept2">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="employees" column="id" ofType="Employee2"
select="com.luo.mybatis._03one2many.mapper.EmployeeMapper.selectByDeptId"/>
</resultMap>
<select id="selectAll2" resultMap="deptResultMap2">
SELECT * FROM t_dept
</select>
</mapper>