2022-05-24  2022-05-24    7253 字   15 分钟

sql片段

sql的配置文件中出现sql冗余

在开发中,SQL的拼接很常见,有很多对拼接的sql具有重复性高的特点,有sql冗余,不仅不美观还导致映射文件配置臃肿,这时最好把重复的sql抽取出来,作为公用的sql片段,尤其在动态sql中应用中更加显著,提高可重用性。

定义sql片段

<!--使用sql标签定义一个sql片段-->
<sql id="baseColumn ">
	id,name,gender,age
</sql>

使用sql片段

<select id="getUsers" resultType="cn.offcn.entity.User">
  select <include refid= "baseColumn"></include> from user
</select>

动态sql语句

动态sql介绍

动态sql的概念

 顾名思义,SQL 是动态拼接成的,根据传入的变量值进行逻辑操作并动态拼接,方便实现多条件下的数据库操作。在业务逻辑复杂,即简单 SQL 无法完成时,需要拼接时就要使用动态SQL。

动态sql解决的问题

 动态sql主要解决根据条件判断附加条动态sql主要解决多条件变化查询,实现自动判断记录字段是否需要更新,根据条件判断附加条sql条件,实现批量添加数据、批量修改数据、批量修删除数据等,优化sql语句,提高执行效率。

构建测试环境

创建maven项目

添加依赖

<dependencies>
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.4.6</version>
</dependency>
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.47</version>
   <scope>runtime</scope>
</dependency>
<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.17</version>
</dependency>
</dependencies>

创建bean

public class User  implements Serializable {  
  
private Integer id;  
private String name;  
private String gender;  
private Integer age;  
private Date birthday;  
  
public User() {}  
  
public User(String name, String gender, Integer age, Date birthday) {  
this.name = name;  
this.gender = gender;  
this.age = age;  
this.birthday = birthday;  
}  
//生成getter和setter方法  
}

创建接口

public interface UserMapper {  
}

编写框架配置文件和sql映射文件

编写框架配置文件

<?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的环境 -->
<environments default="development">
<!-- 配置环境 -->
<environment id="development">
   <!-- 配置事务的类型 -->
   <transactionManager type="JDBC"></transactionManager>
   <!-- 配置连接数据库的信息:用的是数据源【连接池】-->
   <dataSource type="POOLED">
       <property name="driver" value="com.mysql.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://localhost:3306/mybatis001"/>
       <property name="username" value="root"/>
       <property name="password" value="root"/>
   </dataSource>
</environment>
</environments>
<!--  注册UserDao接品映射文件位置 -->
<mappers>
<mapper resource="cn/offcn/mapper/UserMapper.xml"/>
</mappers>
</configuration>x

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="cn.offcn.mapper.UserMapper">  
</mapper>

where标签

where标签简介

where标签用于代替sql中的where关键字,可以根据条件判断是否附加where关键字。如果where标签中有条件成立就会附加where关键字,如果没有成立的条件就不会附加where关键字. 可以去掉离他最近一个无关的and 或or关键字.where标签的书写格式为<where>添写附加条件</where>

where标签使用

编写接口方法findByUser

/**
* 根据User中的字段进行查询
* @return
*/
public List<User> findByUser(User user);

使用where标签进行sql处理

<select id="findByUser" parameterType="cn.offcn.entity.User" resultType="cn.offcn.entity.User">
select * from user
<where>
and name=#{name} and age=#{age}
</where>
</select>

测试findByUser方法

@Test
public void testFindByUser() throws  Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//创建User对象
User user=new User();
user.setName("张三");
user.setAge(22);
List<User> userList = userMapper.findByUser(user);
//遍历
userList.forEach(System.out::print);
//关闭连接
MyBatisUtils.close(session);
}

if标签标签的应用

if标签简介

if标签表示逻辑条件判断,如果条件成立就附加<if></if>之间的sql语句,如果条件不成立就不附加<if></if>之间的sql语句。书写格式为:<if test="表达式">sql语句</if>

if标签使用

编写接口方法findUsersByCondition

/**
* 根据条件查询
* @param user
* @return
*/
    public List<User> findUsersByCondition(User user);

使用if标签进行sql处理

<select id="findUsersByCondition" parameterType="cn.offcn.entity.User" resultType="cn.offcn.entity.User">
select * from user
<where>
   <if test="name!=null">
       name=#{name}
   </if>
   <if test="age!=null">
      and age=#{age}
   </if>
   <if test="name!=null">
      and gender=#{gender}
   </if>
</where>
</select>

测试findUsersByCondition方法

@Test
public void testFindUsersByCondition() throws  Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//创建User对象
User user=new User();
user.setName("王五");
user.setAge(20);
user.setGender("男");
List<User> userList = userMapper.findUsersByCondition(user);
//遍历
userList.forEach(System.out::print);
//关闭连接
MyBatisUtils.close(session);
}

通过产生的sql语句可以看出当if标签中test属性表达式为true时就会附加if标签之间的条件
注意<if>标签的 test 属性中写的是对象的属性名如果是包装类的对象要使用 OGNL 表达式的写法

set标签的应用

set标签简介

set标签用于更新语句中,代替set关键字,可以有效对指定字段进行更新,提升sql的执行效率。,当set标签中有条件成立时就会附加set标签,set标签会去除无关的逗号。set标签中一般嵌套if标签进行使用其格式为  
<set>  
<if test="name">  
name=#{name},  
</if>  
<if test="age">  
age=#{age},  
</if>  
......  
</set>

set标签使用

编写接口方法updateUser

/**  
* 更新user  
* @param user  
*/  
public void updateUser(User user);

使用set标签进行sql处理

<update id="updateUser" parameterType="cn.offcn.entity.User">
  update user 
  <set>
      <if test="name!=null">
          name=#{name}
      </if>
      <if test="gender!=null">
          gender=#{gender}
      </if>
      <if test="age!=null">
          age=#{age}
      </if>
      <if test="birthday!=null">
          birthday=#{birthday}
      </if>
   </set>
      where id=#{id}
</update>

测试updateUser方法

@Test  
public void testUpdateUser() throws  Exception{  
//获取SqlSession对象  
SqlSession session = MyBatisUtils.getSession();  
//调用SqlSession 创建 UserDao接口的代理对象  
UserMapper userMapper = session.getMapper(UserMapper.class);  
//创建User对象  
User user=new User();  
user.setName("王五");  
user.setAge(20);  
//更新user  
userMapper.updateUser(user);  
//提交事务  
MyBatisUtils.close(session);  
//关闭连接  
MyBatisUtils.close(session);  
}  
 
通过产生的sql语句可以看出当set标签中有条件成立时就会附加set关键字字段为null时该列不会被更新set可以忽略与sql无关的逗号

trim标签

trim标签简介

trim标签为万能标签,可用于set或where等。prefix表示要附加的前缀关键字,suffix表示要附加的后缀关键字,prefixOverrides表示要忽略前置字符,suffixOverrides表示要忽略后置字符。  
格式:  
<trim prefix="where" prefixOverrides=",">  
<if test="name!=null">  
name=#{name}  
</if>  
<if test="age!=null">  
age=#{age}  
</if>  
<if test="name!=null">  
gender=#{gender}  
</if>  
</trim>

trim标签使用

修改where标签和set标签

1)应用于where  
<select id="findUsersByCondition" parameterType="cn.offcn.entity.User" resultType="cn.offcn.entity.User">  
select * from user  
<trim prefix="where" prefixOverrides=",">  
<if test="name!=null">  
name=#{name}  
</if>  
<if test="age!=null">  
age=#{age}  
</if>  
<if test="name!=null">  
gender=#{gender}  
</if>  
</trim>  
</select>  
  
2)用于set标签   
<update id="updateUser" parameterType="cn.offcn.entity.User">  
update user  
<trim prefix="set" suffixOverrides=",">  
<if test="name!=null">  
name=#{name},  
</if>  
<if test="gender!=null">  
gender=#{gender},  
</if>  
<if test="age!=null">  
age=#{age},  
</if>  
<if test="birthday!=null">  
birthday=#{birthday}  
</if>  
</trim>  
where id=#{id}  
</update>

测试方法测试updateUser和findUsersByCondition方法

@Test  
public void testFindUsersByCondition() throws  Exception{  
//获取SqlSession对象  
SqlSession session = MyBatisUtils.getSession();  
//调用SqlSession 创建 UserDao接口的代理对象  
UserMapper userMapper = session.getMapper(UserMapper.class);  
//创建User对象  
User user=new User();  
user.setName("王五");  
user.setAge(20);  
user.setGender("男");  
List<User> userList = userMapper.findUsersByCondition(user);  
//遍历  
userList.forEach(System.out::print);  
//关闭连接  
MyBatisUtils.close(session);  
}  
  
@Test  
public void testUpdateUser() throws  Exception{  
//获取SqlSession对象  
SqlSession session = MyBatisUtils.getSession();  
//调用SqlSession 创建 UserDao接口的代理对象  
UserMapper userMapper = session.getMapper(UserMapper.class);  
//创建User对象  
User user=new User();  
user.setName("王五");  
user.setAge(20);  
//更新user  
userMapper.updateUser(user);  
//提交事务  
MyBatisUtils.close(session);  
//关闭连接  
MyBatisUtils.close(session);  
}

choose标签

+ 标签简介

choose标签作用条件判断来拼接指定的条件,它和if不太相同,choose似类于java中的switch语句用法,直要有条件成立,其它判断将得不到执行,如果所有条件都不成立则执行otherwise标签中的内容。  
格式:  
<choose>  
<when test=条件1>  
执行的代码;  
</when>  
<when test=条件2>  
执行的代码;  
</when>  
......  
<otherwise>  
执行的代码;  
</when>  
</otherwise>  
</choose>

choose标签使用

编写接口方法getInfoByUser

/**
* 查询符合条件的所有user对象 
* @param user
* @return
*/
public List<User> getInfoByUser(User user);

使用choose标签进行sql处理

<select id="getInfoByUser" parameterType="cn.offcn.entity.User" resultType="cn.offcn.entity.User">
select * from user
<where>
<choose>
<when test="name!=null">
name=#{name}
</when>
<when test="age!=null">
age=#{age}
</when>
<when test="gender!=null">
gender=#{gender}
</when>
<otherwise>
birthday='1991-10-10'
</otherwise>
</choose>
</where>
</select>

测试接口方法getInfoByUser

@Test
public void testGetInfoByUser() throws  Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//创建User对象
User user=new User();
user.setName("张三");
user.setAge(22);
List<User> userList = userMapper.getInfoByUser(user);
//遍历
userList.forEach(System.out::print);
//关闭连接
MyBatisUtils.close(session);
}

foreach标签

foreach标签简介

foreach标签表示循环,对sql中有重复的部分可以使用此循环来动态拼接sql语句。可以实现批量添加、批量删除、批量更新操作。foreach标签中有很多的属性,请参考下面的Foreach标签属性表。
属性名称 含义
collection 指定你要使用的集合类型
item 集合中每个元素。
open 在起始时,需要附加字符串,只附加一次。
close 在结束时,需要附加字符,只附加一次。
separator 在每个循环结时需要附加的字符串。
index 每个循环的索引值。

foreach标签使用

在接口中创建 addBatchUser、updateBatchUser、deleteBatchUser

/**
     * 批量添加
     * @param userList
     */
    public void addBatchUser(List<User> userList);

    /**
     * 批量更新
     * @param userList
     */
    public void updateBatchUser(List<User> userList);

   /**
     * 批量删除
     * @param ids
     */
    public void deleteBatchUser(List<Integer> ids);

使用forcach标签进行sql处理

<!--批量添加-->
<insert id="addBatchUser">
  insert into user (name,gender,age,birthday) values
  <foreach collection="list" item="user" separator=",">
      (#{user.name},#{user.gender},#{user.age},#{user.birthday})
  </foreach>
</insert>

<!--批量更新-->
<update id="updateBatchUser">
  <foreach collection="list" item="user" separator=";">
      update set user name=#{user.name},gender=#{user.gender},age=#{user.age},birthday=#{user.birthday}
      where id=#{id}
  </foreach>
</update>

<!--批量删除-->
<delete id="deleteBatchUser">
    delete from user where id in
    <foreach collection="list" item="userId" separator="," open="(" close=")">
          #{userId}
    </foreach>
</delete>

测试

//批量添加测试
@Test
public void testAddBatchUser() throws  Exception{
  //获取SqlSession对象
  SqlSession session = MyBatisUtils.getSession();
  //调用SqlSession 创建 UserDao接口的代理对象
  UserMapper userMapper = session.getMapper(UserMapper.class);
  List<User> userList=new ArrayList<>();
  userList.add(new User("赵丽","女",22,new Date()));
  userList.add(new User("李宁","女",25,new Date()));
  userList.add(new User("王海涛","男",20,new Date()));
  userMapper.addBatchUser(userList);
  //提交事务
  session.commit();
  //关闭连接
  MyBatisUtils.close(session);
}

//批量更新测试
@Test
public void testUpdateBatchUser() throws  Exception{
  //获取SqlSession对象
  SqlSession session = MyBatisUtils.getSession();
  //调用SqlSession 创建 UserDao接口的代理对象
  UserMapper userMapper = session.getMapper(UserMapper.class);
  List<User> userList=new ArrayList<>();
  userList.add(new User(1,"赵刚","男",24,new Date()));
  userList.add(new User(2,"白雪","女",25,new Date()));
  userList.add(new User(3,"王海燕","女",20,new Date()));
  userMapper.updateBatchUser(userList);
  //提交事务
  session.commit();
  //关闭连接
  MyBatisUtils.close(session);
}

//批量删除测试
@Test
public void testDeleteBatchUser() throws  Exception{
  //获取SqlSession对象
  SqlSession session = MyBatisUtils.getSession();
  //调用SqlSession 创建 UserDao接口的代理对象
  UserMapper userMapper = session.getMapper(UserMapper.class);
  List<Integer> ids=Arrays.asList(1,2,3);
  userMapper.deleteBatchUser(ids);
  //提交事务
  session.commit();
  //关闭连接
  MyBatisUtils.close(session);
}

注意mysql本身不支持批量更新如果需要批量更新时在url中附加allowMultiQueries=true
<property name="url" value="jdbc:mysql:///mybatis002?allowMultiQueries=true"/>

多表联合查询

多表联合查询概述

在开发过程中单表查询不能满足项目需求分析功能,对于复杂业务来讲,关联的表有几张,甚至几十张并且表与表之间的关系相当复杂。为了能够实业复杂功能业务,就必须进行多表查询,在mybatis中提供了多表查询的结果时映射标签,可以实现表之间的一对一、一对多、多对一、多对多关系映射。

MyBatis多表查询之一对一

构建数据库表:person(个人表) IdCard(身份证表)

#person表
CREATE TABLE person(
p_id INT NOT NULL AUTO_INCREMENT,
p_name VARCHAR(30),
PRIMARY KEY(p_id)
);

#IdCard表
CREATE TABLE idcard(
c_id INT NOT NULL AUTO_INCREMENT,
c_cardno VARCHAR(18),
c_uselife DATE,
c_person_id INT NOT NULL,
PRIMARY KEY(c_id),
FOREIGN KEY(c_person_id) REFERENCES person(p_id),
UNIQUE KEY(c_cardno),
UNIQUE KEY(c_person_id)
);

INSERT INTO person(p_name) VALUES('张三'),('李四');

INSERT INTO idcard(c_cardno,c_uselife,c_person_id)
VALUES('110112199012127821','2029-10-10',1);
INSERT INTO idcard(c_cardno,c_uselife,c_person_id)
VALUES('120114199911103491','2030-12-01',2);

准备项目环境

构建maven项目,添加依赖

<dependencies>
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.4.6</version>
</dependency>
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.47</version>
   <scope>runtime</scope>
</dependency>
<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.17</version>
</dependency>
</dependencies>

编写框架配置文件sqlMapConfig.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>
<!-- 配置 mybatis的环境 -->
<environments default="development">
<!-- 配置环境 -->
<environment id="development">
   <!-- 配置事务的类型 -->
   <transactionManager type="JDBC"></transactionManager>
   <!-- 配置连接数据库的信息:用的是数据源连接池-->
   <dataSource type="POOLED">
       <property name="driver" value="com.mysql.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://localhost:3306/mybatis002"/>
       <property name="username" value="root"/>
       <property name="password" value="root"/>
   </dataSource>
</environment>
</environments>
<mappers>
<package name="cn.offcn.dao"></package>
</mappers
</configuration>

方式一:嵌套结果方式

创建数据模型Person,IdCard

package cn.offcn.entity;

public class Person {

private int id;
private String name;


public int getId() {
  return id;
}

public void setId(int id) {
  this.id = id;
}

public String getName() {
  return name;
}

public void setName(String name) {
  this.name = name;
}

}
public class IdCard {

private int id;
private String cardno;
private Date useLife;


public int getId() {
  return id;
}

public void setId(int id) {
  this.id = id;
}

public String getCardno() {
  return cardno;
}

public void setCardno(String cardno) {
  this.cardno = cardno;
}

public Date getUseLife() {
  return useLife;
}

public void setUseLife(Date useLife) {
  this.useLife = useLife;
}

}

编写sql语句

实现查询个人信息时,也要查询个人所对应的身份证信息。
select p.*,c.* from 
person p,
idcard c
where p.p_id=c.c_person_id and p.p_id=1;

编写PersonIdCard类

public class PersonIdCard extends Person{

private String cardno;
private Date useLife;
public String getCardno() {
  return cardno;
}

public void setCardno(String cardno) {
  this.cardno = cardno;
}

public Date getUseLife() {
  return useLife;
}

public void setUseLife(Date useLife) {
  this.useLife = useLife;
}
}

定义持久层接口PersonDao

public interface PersonDao{

/**
    * 根据id查询person对象
    */
    public PersonIdCard getPersonById(int id);
}

定义 PersonDao.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="cn.offcn.dao.PersonDao">
<!-- 配置查询操作-->
<select id="getPersonById" resultMap="PersonResultMap">
select p.*,c.* from 
person p,
idcard c
where p.p_id=c.c_person_id and p.p_id=#{id};
</select>
<resultMap id="PersonResultMap" type="cn.offcn.entity.PersonIdCard">
<id column="p_id" property="id"></id>
<result column="p_id" property="id"></result>
<result column="p_name" property="name"></result>
<result column="c_cardno" property="cardno"></result>
<result column="c_uselife" property="useLife"></result>
</resultMap>
</mapper>

创建 PersonTest 测试类

@Test
public void testGetPersonById() throws  Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
PersonDao personDao = session.getMapper(PersonDao.class);
PersonIdCard personIdCard=personDao.getPersonById(1);
//打印
System.out.println(personIdCard);
//提交事务
session.commit();
//关闭连接
MyBatisUtils.close(session);
}

方式二:嵌套查询方式

修改Person类:添加idCard属性

public class Person {

private int id;
private String name;
private IdCard idCard;

public int getId() {
  return id;
}

public void setId(int id) {
  this.id = id;
}

public String getName() {
  return name;
}

public void setName(String name) {
  this.name = name;
}
public IdCard getIdCard() {
  return idCard;
}

public void setIdCard(IdCard idCard) {
  this.idCard = idCard;
}

}

修改 PersonDao 接口中的方法

public interface PersonDao{

/**
    * 根据id查询person对象
    */
    public Person getPersonById(int id);
}

定义身份证的持久层接口IdCardDao

public interface IdCardDao{
    
    /**
    * 根据c_person_id查询IdCard对象
    */
    public Person getIdCardByPersonId(int id);
}

定义 IdCardDao.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="cn.offcn.dao.IdCard">
<!-- 配置查询操作-->
<select id="getIdCardByPersonId" resultMap="IdCardResultMap">
select * from 
idcard c
where c_person_id=#{id};
</select>
<resultMap id="IdCardResultMap" type="cn.offcn.entity.IdCard">  
  <id column="c_id" property="id"></id>
  <result column="c_cardno" property="cardno"></result>
  <result column="c_uselife" property="useLife"></result>
</resultMap>
</mapper>

修改PersonDao.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="cn.offcn.dao.PersonDao">
<!-- 配置查询操作-->
<select id="getPersonById" resultMap="PersonResultMap">
select * from 
person p,
where p_id=#{id};
</select>
<resultMap id="PersonResultMap" type="cn.offcn.entity.Person">
<id column="p_id" property="id"></id>
<result column="p_id" property="id"></result>
<result column="p_name" property="name"></result>
<!--映射Person类中的复杂字段idCard对象属性-->
<association property="idCard" javaType="IdCard" column="p_id" 
           select="cn.offcn.dao.IdCard.getIdCardByPersonId">
</association>
</resultMap>
</mapper>

column:表示取上次查询出来的指定列的值,做为select属性所指定的查询的输入值。
select:表示指定的查询.

PersonTest 类中加入测试方法

@Test
public void testGetPersonById() throws  Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
PersonDao personDao = session.getMapper(PersonDao.class);
Person person=personDao.getPersonById(1);
//打印
System.out.println(person);
//提交事务
session.commit();
//关闭连接
MyBatisUtils.close(session);
}

MyBatis实现一对多查询

创建数据库表:department(部门表),employee(员工表)同时设定部门和员工表的关系

CREATE TABLE department(
d_id INT NOT NULL AUTO_INCREMENT,
d_name VARCHAR(100),
PRIMARY KEY(d_id)
);

CREATE TABLE employee(
e_id INT NOT NULL AUTO_INCREMENT,
e_name VARCHAR(30),
e_gender VARCHAR(6),
e_age INT,
e_depart_id INT,
PRIMARY KEY(e_id),
FOREIGN KEY(e_depart_id) REFERENCES department(d_id)
);

方式一:嵌套结果的方式

创建数据模型department和employee

public class Department {

private int id;
private String name;
public int getId() {
  return id;
}

public void setId(int id) {
  this.id = id;
}

public String getName() {
  return name;
}

public void setName(String name) {
  this.name = name;
}


}

public class Employee {

private int id;
private String name;
private String gender;
private Integer age;
public Employee(){}

public Employee(int id,String name, String gender, int age) {
  this.id=id;
  this.name = name;
  this.gender = gender;
  this.age = age;
}
public Employee(String name, String gender, int age) {
  this.name = name;
  this.gender = gender;
  this.age = age;
}

public int getId() {
  return id;
}

public void setId(int id) {
  this.id = id;
}

public String getName() {
  return name;
}

public void setName(String name) {
  this.name = name;
}

public String getGender() {
  return gender;
}

public void setGender(String gender) {
  this.gender = gender;
}

public Integer getAge() {
  return age;
}

public void setAge(Integer age) {
  this.age = age;
}
}

编写一对多的sql查询语句

SELECT d.*,e.* 
FROM 
department d, employee e 
WHERE
e.e_depart_id=d.d_id AND d.d_id=#{id}

Department类中加入List<Employee>属性

private List<Employee> emps;
public List<Employee> getEmps() {
  return emps;
}

public void setEmps(List<Employee> emps) {
  this.emps = emps;
}

部门持久层DepartmentDao 接口中加入查询方法

import cn.offcn.entity.Department;

public interface DepartmentMapper {
public Department getDepartmentById(int id);
} 

部门持久层 DepartmentDao.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="cn.offcn.mapper.DepartmentDao">
 <select id="getDepartmentById" resultMap="DepartemntResultMap2">
     SELECT d.*,e.* FROM department d, employee e WHERE
     e.e_depart_id=d.d_id AND d.d_id=#{id}
 </select>
<resultMap id="DepartemntResultMap" type="Department">
    <id column="d_id" property="id"></id>
    <result column="d_name" property="name"></result>
    <collection property="emps" ofType="Employee">
         <id column="e_id" property="id"></id>
         <result column="e_name" property="name"></result>
         <result column="e_gender" property="gender"></result>
         <result column="e_age" property="age"></result>
    </collection>
</resultMap>
collection:当属性为集合时,使用collection标签进行映射。

测试方法

 @Test
 public void testGetDepartentById() throws  Exception{
     //获取SqlSession对象
     SqlSession session = MyBatisUtils.getSession();
     //调用SqlSession 创建 UserDao接口的代理对象
     DepartmentDao departmentDao = session.getMapper(DepartmentDao.class);
     Department dept=departmentDao.getDepartentById(1);
     //打印
     System.out.println(dept);
     //提交事务
     session.commit();
     //关闭连接
     MyBatisUtils.close(session);
 }

方式二:嵌套查询的方式

定义员工的持久层接口EmployeeDao

public interface EmployeeDao {
public List<Employee> getEmployeeByDepartId(int id);
}

定义 EmployeeDao.xml 文件中的查询配置信息

<select id="getEmployeeByDepartId" resultType="Employee">
    select e_id id,e_name name,e_gender gender,e_age age
    from employee where e_depart_id=#{id}
</select>

修改DepartmentDao.xml配置文件

<select id="getDepartmentById" resultMap="DepartemntResultMap">
    select * from department where d_id=#{id}
 </select>
<resultMap id="DepartemntResultMap" type="Department">
     <id column="d_id" property="id"></id>
     <result column="d_name" property="name"></result>
     <collection property="emps" ofType="Employee" column="d_id"
              select="cn.offcn.mapper.EmployeeMapper.getEmployeeByDepartId">
     </collection>
</resultMap>

此处变为单表查询,使分表查询方式进行查询。

测试方法

@Test
public void testGetDepartentById() throws  Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
DepartmentDao departmentDao = session.getMapper(DepartmentDao.class);
Department dept=departmentDao.getDepartentById(1);
//打印
System.out.println(dept);
//提交事务
session.commit();
//关闭连接
MyBatisUtils.close(session);
}

MyBatis实现多对多查询

创建数据库表:student(学生表),teacher(老师表)

CREATE TABLE student(
 sid INT NOT NULL AUTO_INCREMENT,
 sname VARCHAR(30),
 PRIMARY KEY(sid)
);

CREATE TABLE teacher(
 tid INT NOT NULL AUTO_INCREMENT,
 tname VARCHAR(30),
 PRIMARY KEY(tid)
);

CREATE TABLE student_teacher(
 s_id INT NOT NULL,
 t_id INT NOT NULL,
 PRIMARY KEY(s_id,t_id),
 FOREIGN KEY(s_id) REFERENCES student(sid),
 FOREIGN KEY(t_id) REFERENCES teacher(tid)
);
INSERT INTO student(sname) VALUES('张三'),('李四');
INSERT INTO teacher (tname) VALUES('刘老师'),('李老师');
INSERT INTO student_teacher(s_id,t_id) 
VALUES(1,1),(1,2),(2,1)

方式一:嵌套结果方式

创建数据模型:Student,Teacher,StudentTeacher

public class Student {

 private int id;
 private String name;
 public int getId() {
     return id;
 }

 public void setId(int id) {
     this.id = id;
 }

 public String getName() {
     return name;
 }

 public void setName(String name) {
     this.name = name;
 }
}

public class Teacher {

 private int id;
 private String name;
 public int getId() {
     return id;
 }

 public void setId(int id) {
     this.id = id;
 }

 public String getName() {
     return name;
 }

 public void setName(String name) {
     this.name = name;
 }
}

public class StudentTeacher {
 private int sid;
 private int tid;
 public int getSid() {
     return sid;
 }

 public void setSid(int sid) {
     this.sid = sid;
 }

 public int getTid() {
     return tid;
 }

 public void setTid(int tid) {
     this.tid = tid;
 }

编写多对多的sql语句

SELECT s.*,ts.*,t.* 
FROM 
student s,student_teacher st,teacher t
WHERE 
s.sid=st.s_id AND st.t_id=t.tid AND s.sid=1

Student类中加入List<StudentTeacher>属性

private List<StudentTeacher> studentTeacherList;
public List<StudentTeacher> getStudentTeacherList() {
     return studentTeacherList;
}
public void setStudentTeacherList(List<StudentTeacher> studentTeacherList) {
     this.studentTeacherList = studentTeacherList;
}

StudentTeacher中加入Teacher属性

private Teacher teacher;
public Student getStudent() {
     return student;
}
public void setStudent(Student student) {
     this.student = student;
}

学生持久层StudentDao接口中加入查询方法

import cn.offcn.entity.Student;
public interface StudentDao {
 public Student getStudentById(int id);
}

学生持久层SudentDao.xml映射文件配置

<select id="getStudentById" resultMap="StudentResultMap">
     SELECT s.*,ts.*,t.* FROM student s,teacher_student ts,teacher t
     WHERE s.sid=ts.s_id AND ts.t_id=t.tid AND s.sid=#{id}
 </select>
 <resultMap id="StudentResultMap" type="Student">
      <id column="sid" property="id"></id>
      <result column="sname" property="name"/>
      <collection property="studentTeacherList" ofType="StudentTeacher">
           <result column="s_id" property="sid"></result>
           <result column="t_id" property="tid"></result>
           <association property="teacher" javaType="Teacher">
               <id column="tid" property="id"></id>
               <result column="tname" property="name"></result>
           </association>
      </collection>
 </resultMap>

测试

@Test
public void testGetStudentById() throws  Exception{
  //获取SqlSession对象
  SqlSession session = MyBatisUtils.getSession();
  //调用SqlSession 创建 StudentDao接口的代理对象
  StudentDao studentDao = session.getMapper(StudentDao.class);
  Student student= studentDao.getStudentById(1);
  //打印
  System.out.println(tudent);
  //提交事务
  session.commit();
  //关闭连接
  MyBatisUtils.close(session);
}

方式二:嵌套查询方式

定义中间表的持久层接口StudentTeacherDao

public interface StudentTeacherDao {
 public List<StudentTeacher> getStudentTeacherBySid(int sid);
}

定义StudentTeacherDao.xml文件中的查询配置信息

<!DOCTYPE mapper
     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.offcn.dao.StudentTeacherDao">

 <select id="getStudentTeacherBySid" resultMap="StudentTeacherResultMap">
      select * from teacher_student where s_id=#{sid}
 </select>
 <resultMap id="StudentTeacherResultMap" type="StudentTeacher">
        <result column="s_id" property="sid"></result>
        <result column="t_id" property="tid"></result>
        <association property="teacher" javaType="Teacher"
          column="t_id" select="cn.offcn.dao.TeacherMapper.getTeacherByTid">              </association>
 </resultMap>
</mapper>

定义老师持久层的接口TeacherDao

public interface TeacherDao {

 public Teacher getTeacherByTid(int tid);
}

定义老师持久层TeacherDao.xml映射文件配置

<!DOCTYPE mapper
     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.offcn.dao.TeacherDao">
 <select id="getTeacherByTid" resultType="Teacher">
         select tid id,tname name from teacher where tid=#{tid}
 </select>
</mapper>

修改StudentDao持久层的方法

public interface StudentMapper {
 public Student getStudentById(int id);
}

修改StudentDao.xml的查询配置信息

<select id="getStudentById" resultMap="StudentResultMap">
       select * from student where sid=#{id}
 </select>
 <resultMap id="StudentResultMap" type="Student">
     <id column="sid" property="id"></id>
     <result column="sname" property="name"/>
     <collection property="studentTeacherList" ofType="StudentTeacher"
     column="sid"
     select="cn.offcn.mapper.StudentTeacherMapper.getStudentTeacherBySid">
     </collection>
 </resultMap>

测试方法

@Test
public void testGetStudentById() throws  Exception{
  //获取SqlSession对象
  SqlSession session = MyBatisUtils.getSession();
  //调用SqlSession 创建 StudentDao接口的代理对象
  StudentDao studentDao = session.getMapper(StudentDao.class);
  Student student= studentDao.getStudentById(1);
  //打印
  System.out.println(tudent);
  //提交事务
  session.commit();
  //关闭连接
  MyBatisUtils.close(session);
}

avatar
青山
悟已往之不谏 知来者之可追
一言
今日诗词
站点信息
本站访客数 :
本站总访问量 :