Mybatis

一、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>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值