SSM框架学习——MyBatis关联映射

MyBatis关联映射

为什么要关联映射

实际开发中,对数据库操作常常会涉及多张表,所以在OOP中就涉及对象与对象的关联关系。针对多表操作,MyBatis提供关联映射。

关联关系概述

  • 一对一:A类中定义B类的属性b,B类中定义A类属性a。
  • 一对多:一个A类类型对应多个B类。
  • 多对多:在A类中定义B的集合,B中定义A的集合。

嵌套查询与嵌套结果

嵌套查询是通过执行另外一条SQL映射语句来返回预期复杂类型:

  • 嵌套查询是在查询SQL嵌套一个子查询
  • 嵌套查询会执行多条SQL语句
  • 嵌套查询SQL语句编写相对简单

嵌套结果是使用嵌套结果映射来处理的联合结果子集:

  • 嵌套结果是一个嵌套的多表查询SQL
  • 嵌套结果只会执行一条复杂的SQL语句
  • 嵌套结果SQL语句写起来相对麻烦

对于嵌套查询有一个问题,那就是执行多条SQL语句导致性能开销很大。于是就有了MyBatis的延迟加载——fetchType。

实践

创建表

我们还是用之前的账户连接数据库,终端命令可以如下

mysql -u db_mybatis -p

输入密码敲击回车,然后切换数据库到db_mybatis

Windows用户可以用终端或者sqlyog执行下面语句

如果你没有这个数据库请回到前面的章节创建它。

USE db_mybatis;

我们要使用一个新的customer表,所以把之前项目留下的删除掉

DROP TABLE IF EXISTS customer;

重新创建它

CREATE TABLE customer(`id` int(32) NOT NULL AUTO_INCREMENT,`username` varchar(50) DEFAULT NULL,`jobs` varchar(50) DEFAULT NULL,`phone` varchar(16) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

给这张表插入两条数据方便我们接下来写代码用

INSERT  INTO customer(`id`,`username`,`jobs`,`phone`) VALUES (1,'zhangsan','teacher','11111111111'),(2,'lisi','student','11111111112');

创建一张idcard表,并设置主键(主码)为id

如果之前存在请删除

DROP TABLE IF EXISTS `idcard`;
CREATE TABLE idcard(`id` int(11) NOT NULL AUTO_INCREMENT,`code` varchar(50) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

同样插入两条数据(身份证号是我瞎编的,为了防止巧合不一定符合真实格式,但长度与现实一样)

INSERT  INTO idcard(`id`,`code`) VALUES(1,'37010219800X051118'),(2,'370203199X09092222');

创建persion表,并插入数据

DROP TABLE IF EXISTS person;CREATE TABLE person(`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(50) DEFAULT NULL,`age` int(11) DEFAULT NULL,`card_id` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `FK_person` (`card_id`),CONSTRAINT `FK_person` FOREIGN KEY (`card_id`) REFERENCES `idcard` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;INSERT INTO person(`id`,`name`,`age`,`card_id`) values (1,'张三',18,1),(2,'李四',18,2);

创建product表并插入数据

DROP TABLE IF EXISTS product;CREATE TABLE product(`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) DEFAULT NULL,`price` double DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;INSERT INTO product(`id`,`name`,`price`) values (1,'笔记本电脑',8888.8),(2,'华为手机',6666.6);

创建user表并插入数据

DROP TABLE IF EXISTS user;CREATE TABLE user(`id` int(11) NOT NULL,`name` varchar(20) DEFAULT NULL,`password` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO user(`id`,`name`,`password`) values (1,'zhangsan','654321'),(2,'lisi','123456');

创建orders

DROP TABLE IF EXISTS orders;
CREATE TABLE orders(`id` int(11) NOT NULL AUTO_INCREMENT,`number` varchar(32) DEFAULT NULL,`user_id` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `FK_orders` (`user_id`),CONSTRAINT `FK_orders` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;INSERT INTO `orders`(`id`,`number`,`user_id`) VALUES (1,'201901',1);

创建orderitem表,还是一样,如果之前存在先删除。这个表一定放后面,否则创建外键会报错。

DROP TABLE IF EXISTS orderitem;CREATE TABLE orderitem(`id` int(11) NOT NULL AUTO_INCREMENT,`orders_id` int(11) DEFAULT NULL,`product_id` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `FK_orderitem` (`orders_id`),KEY `FK_orderitem_product` (`product_id`),CONSTRAINT `FK_orderitem_product` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`),CONSTRAINT `FK_orderitem` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;INSERT INTO orderitem(`id`,`orders_id`,`product_id`) VALUES (1,1,1),(2,1,2);

构建项目

我们新创建一个Maven项目top.cairbin.test5

pom.xml添加依赖包

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>top.cairbin</groupId><artifactId>test5</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>test5</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.4</version></dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core --><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.4.0</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency></dependencies>
</project>

创建与src平级的resources目录,并右键->Build Path->Use as Source Folder

在里面添加一个数据库配置文件db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis
jdbc.username=db_mybatis
jdbc.password=db_mybatis

配置MyBatis,在同目录下创建mybatis-config.xml,这个文件会使用db.properties里面的配置,以${...}的方式调用,在<properties resource="db.properties" />里声明位置。

<?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><properties resource="db.properties" /><settings><!-- 延迟加载的开关 --><setting name="lazyLoadingEnabled" value="false" /><!-- 设置积极加载(true)或按需加载(false) --><setting name="aggressiveLazyLoading" value="true" /><setting name="mapUnderscoreToCamelCase" value="true" /><setting name="logImpl" value="STDOUT_LOGGING" /></settings><typeAliases><package name="top.cairbin.test5" /></typeAliases><!--1.配置环境 ,默认的环境id为mysql --><environments default="mysql"><!--1.2.配置id为mysql的数据库环境 --><environment id="mysql"><!-- 使用JDBC的事务管理 --><transactionManager type="JDBC" /><!--数据库连接池 --><dataSource type="POOLED"><!-- 数据库驱动 --><property name="driver" value="${jdbc.driver}" /><!-- 连接数据库的url --><property name="url" value="${jdbc.url}" /><!-- 连接数据库的用户名 --><property name="username" value="${jdbc.username}" /><!-- 连接数据库的密码 --><property name="password" value="${jdbc.password}" /></dataSource></environment></environments><!--2.配置Mapper的位置 --><mappers><mapper resource="top/cairbin/test5/mapper/CustomerMapper.xml" /><mapper resource="top/cairbin/test5/mapper/UserMapper.xml" /><mapper resource="top/cairbin/test5/mapper/IdCardMapper.xml" /><mapper resource="top/cairbin/test5/mapper/OrdersMapper.xml" /><mapper resource="top/cairbin/test5/mapper/PersonMapper.xml" /><mapper resource="top/cairbin/test5/mapper/ProductMapper.xml" /></mappers>
</configuration>

注意上方的<mapper>的目录,我们一会介绍。

然后添加log4j的配置文件log4j.properties

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.top.cairbin.test5=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

Dao层

我们先把对应的类创建了再说,到src/main/javatop.cairbin.test5创建一个子包,名称为top.cairbin.test5.dao

在我们新创建的包下面编写若干个类

首先是Person类,此时我们的IdCard还没创建,IDE提示错误很正常

package top.cairbin.test5.dao;public class Person {private Integer id;private String name;private Integer age;private Integer cardId;private IdCard card;public void setId(Integer id) {this.id = id;}public Integer getId() {return this.id;}public void setName(String name) {this.name = name;}public String getName() {return this.name;}public void setAge(Integer age) {this.age = age;}public Integer getAge() {return this.age;}public Integer getCardId() {return cardId;}public void setCardId(Integer cardId) {this.cardId = cardId;}public void setCard(IdCard card) {this.card = card;}public IdCard getCard() {return this.card;}	
}

接下来创建IdCard

package top.cairbin.test5.dao;public class IdCard {private Integer id;private String code;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getCode() {return code;}public void setCode(String code) {this.code = code == null ? null : code.trim();}
}

然后是Customer

package top.cairbin.test5.dao;public class Customer {private Integer id;private String username;private String jobs;private String phone;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username == null ? null : username.trim();}public String getJobs() {return jobs;}public void setJobs(String jobs) {this.jobs = jobs == null ? null : jobs.trim();}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone == null ? null : phone.trim();}
}

接着是Orders

package top.cairbin.test5.dao;package top.cairbin.test5.dao;import java.util.List;public class Orders {private Integer id;private String number;private Integer userId;private List<Product> productList;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getNumber() {return number;}public void setNumber(String number) {this.number = number == null ? null : number.trim();}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public void setProductList(List<Product> productList) {this.productList = productList;}public List<Product> getProductList(){return this.productList;}   
}

Product

package top.cairbin.test5.dao;public class Product {private Integer id;private String name;private Double price;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name == null ? null : name.trim();}public Double getPrice() {return price;}public void setPrice(Double price) {this.price = price;}
}

User

package top.cairbin.test5.dao;import java.util.List;public class User {private Integer id;private String name;private String password;private List<Orders> ordersList;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name == null ? null : name.trim();}public String getPassword() {return password;}public void setPassword(String password) {this.password = password == null ? null : password.trim();}public void setOrdersList(List<Orders> ordersList) {this.ordersList = ordersList;}public List<Orders> getOrdersList(){return this.ordersList;}   
}

Util层

这一层我们来放置一些工具类。创建包top.cairbin.test5.util

然后在下面创建MyBatisHelper

package top.cairbin.test5.util;import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisHelper {private static SqlSessionFactory sqlSessionFactory = null;// 初始化SqlSessionFactory对象static {try {// 使用MyBatis提供的Resources类加载MyBatis的配置文件Reader reader = Resources.getResourceAsReader("mybatis-config.xml");// 构建SqlSessionFactory工厂sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (Exception e) {e.printStackTrace();}}// 获取SqlSession对象的静态方法public static SqlSession getSession() {return sqlSessionFactory.openSession();}
}

Mapper层

接下来我们再为top.cairbin.test5创建一个子包top.cairbin.test5.mapper,该层主要实现数据持久化。

与上面不一样的是,我们这里定义的是接口

首先是CustomerMapper接口

package top.cairbin.test5.mapper;import top.cairbin.test5.dao.Customer;public interface CustomerMapper {int deleteByPrimaryKey(Integer id);int insert(Customer record);int insertSelective(Customer record);Customer selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(Customer record);int updateByPrimaryKey(Customer record);
}

到这里你可能会问,谁去实现它们呢,还记得mybatis-config.xml里那些<mapper>吗,它们每一个都指定resource到Mapper层,也就是说我们要在这里写XML文件让MyBatis实现这些方法。

第一个是CustomerMapper.xml,注意此处的namespace<resultMap>id,下文同理。

<?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="top.cairbin.test5.mapper.CustomerMapper"><resultMap id="BaseResultMap" type="top.cairbin.test5.dao.Customer"><id column="id" jdbcType="INTEGER" property="id" /><result column="username" jdbcType="VARCHAR" property="username" /><result column="jobs" jdbcType="VARCHAR" property="jobs" /><result column="phone" jdbcType="VARCHAR" property="phone" /></resultMap><sql id="Base_Column_List">id, username, jobs, phone</sql><select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">select <include refid="Base_Column_List" />from customerwhere id = #{id,jdbcType=INTEGER}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">delete from customerwhere id = #{id,jdbcType=INTEGER}</delete><insert id="insert" parameterType="top.cairbin.test5.dao.Customer">insert into customer (id, username, jobs, phone)values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{jobs,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR})</insert><insert id="insertSelective" parameterType="top.cairbin.test5.dao.Customer">insert into customer<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="username != null">username,</if><if test="jobs != null">jobs,</if><if test="phone != null">phone,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="username != null">#{username,jdbcType=VARCHAR},</if><if test="jobs != null">#{jobs,jdbcType=VARCHAR},</if><if test="phone != null">#{phone,jdbcType=VARCHAR},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.Customer">update customer<set><if test="username != null">username = #{username,jdbcType=VARCHAR},</if><if test="jobs != null">jobs = #{jobs,jdbcType=VARCHAR},</if><if test="phone != null">phone = #{phone,jdbcType=VARCHAR},</if></set>where id = #{id,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.Customer">update customerset username = #{username,jdbcType=VARCHAR},jobs = #{jobs,jdbcType=VARCHAR},phone = #{phone,jdbcType=VARCHAR}where id = #{id,jdbcType=INTEGER}</update>
</mapper>

对了,请检查你XML中的方法的parameterType属性以及resultType对应类型的包是否正确!!!

然后是IdCardMapper接口

package top.cairbin.test5.mapper;import top.cairbin.test5.dao.IdCard;public interface IdCardMapper {int deleteByPrimaryKey(Integer id);int insert(IdCard record);int insertSelective(IdCard record);IdCard selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(IdCard record);int updateByPrimaryKey(IdCard record);
}

同样在IdCardMapper.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="top.cairbin.test5.mapper.IdCardMapper"><resultMap id="BaseResultMap" type="top.cairbin.test5.dao.IdCard"><id column="id" jdbcType="INTEGER" property="id" /><result column="code" jdbcType="VARCHAR" property="code" /></resultMap><sql id="Base_Column_List">id, code</sql><select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">select <include refid="Base_Column_List" />from idcardwhere id = #{id,jdbcType=INTEGER}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">delete from idcardwhere id = #{id,jdbcType=INTEGER}</delete><insert id="insert" parameterType="top.cairbin.test5.dao.IdCard">insert into idcard (id, code)values (#{id,jdbcType=INTEGER}, #{code,jdbcType=VARCHAR})</insert><insert id="insertSelective" parameterType="top.cairbin.test5.dao.IdCard">insert into idcard<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="code != null">code,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="code != null">#{code,jdbcType=VARCHAR},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.IdCard">update idcard<set><if test="code != null">code = #{code,jdbcType=VARCHAR},</if></set>where id = #{id,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.IdCard">update idcardset code = #{code,jdbcType=VARCHAR}where id = #{id,jdbcType=INTEGER}</update>
</mapper>

然后是ProductMapper接口以及ProductMapper.xml

package top.cairbin.test5.mapper;
import top.cairbin.test5.dao.Product;public interface ProductMapper {int deleteByPrimaryKey(Integer id);int insert(Product record);int insertSelective(Product record);Product selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(Product record);int updateByPrimaryKey(Product record);
}
<?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="top.cairbin.test5.mapper.ProductMapper"><resultMap id="BaseResultMap" type="top.cairbin.test5.dao.Product"><id column="id" jdbcType="INTEGER" property="id" /><result column="name" jdbcType="VARCHAR" property="name" /><result column="price" jdbcType="DOUBLE" property="price" /></resultMap><sql id="Base_Column_List">id, name, price</sql><select id="findProductByOrderId" parameterType="Integer"   resultType="Product">SELECT * from product where id IN(SELECT product_id FROM orderitem  WHERE orders_id = #{id})</select><select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">select <include refid="Base_Column_List" />from productwhere id = #{id,jdbcType=INTEGER}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">delete from productwhere id = #{id,jdbcType=INTEGER}</delete><insert id="insert" parameterType="top.cairbin.test5.dao.Product">insert into product (id, name, price)values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{price,jdbcType=DOUBLE})</insert><insert id="insertSelective" parameterType="top.cairbin.test5.dao.Product">insert into product<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="name != null">name,</if><if test="price != null">price,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="name != null">#{name,jdbcType=VARCHAR},</if><if test="price != null">#{price,jdbcType=DOUBLE},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.Product">update product<set><if test="name != null">name = #{name,jdbcType=VARCHAR},</if><if test="price != null">price = #{price,jdbcType=DOUBLE},</if></set>where id = #{id,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.Product">update productset name = #{name,jdbcType=VARCHAR},price = #{price,jdbcType=DOUBLE}where id = #{id,jdbcType=INTEGER}</update>
</mapper>

对于剩下来的几个Dao层类对应的Mapper需要特别注意下,因为它们的类里都包含复合类型,这也是我们这一章节真正要学习的东西——关联映射。

PersonMapper接口

package top.cairbin.test5.mapper;import top.cairbin.test5.dao.Person;public interface PersonMapper {int deleteByPrimaryKey(Integer id);int insert(Person record);int insertSelective(Person record);Person selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(Person record);int updateByPrimaryKey(Person record);
}

PersonMapper.xml文件,请重点关注findPersonByIdfindPersonById2这两个地方。

<?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="top.cairbin.test5.mapper.PersonMapper"><resultMap id="BaseResultMap" type="top.cairbin.test5.dao.Person"><id column="id" jdbcType="INTEGER" property="id" /><result column="name" jdbcType="VARCHAR" property="name" /><result column="age" jdbcType="INTEGER" property="age" /><result column="card_id" jdbcType="INTEGER" property="cardId" /></resultMap><sql id="Base_Column_List">id, name, age, card_id</sql><!-- 嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 --><select id="findPersonById" parameterType="Integer" resultMap="IdCardWithPersonResult">SELECT * from person where id=#{id}</select><resultMap type="Person" id="IdCardWithPersonResult"><id property="id" column="id" /><result property="name" column="name" /><result property="age" column="age" /><!-- 一对一:association使用select属性引入另外一条SQL语句 --><association property="card" column="card_id" javaType="top.cairbin.test5.dao.IdCard"select="top.cairbin.test5.mapper.IdCardMapper.selectByPrimaryKey" /></resultMap><!-- 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集 --><select id="findPersonById2" parameterType="Integer" resultMap="IdCardWithPersonResult2">SELECT p.*,idcard.codefrom person p,idcard idcardwhere p.card_id=idcard.id and p.id= #{id}</select><resultMap type="Person" id="IdCardWithPersonResult2"><id property="id" column="id" /><result property="name" column="name" /><result property="age" column="age" /><association property="card" javaType="IdCard"><id property="id" column="id" /><result property="code" column="code" /></association></resultMap><select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">select <include refid="Base_Column_List" />from personwhere id = #{id,jdbcType=INTEGER}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">delete from personwhere id = #{id,jdbcType=INTEGER}</delete><insert id="insert" parameterType="top.cairbin.test5.dao.Person">insert into person (id, name, age, card_id)values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}, #{cardId,jdbcType=INTEGER})</insert><insert id="insertSelective" parameterType="top.cairbin.test5.dao.Person">insert into person<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="name != null">name,</if><if test="age != null">age,</if><if test="cardId != null">card_id,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="name != null">#{name,jdbcType=VARCHAR},</if><if test="age != null">#{age,jdbcType=INTEGER},</if><if test="cardId != null">#{cardId,jdbcType=INTEGER},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.Person">update person<set><if test="name != null">name = #{name,jdbcType=VARCHAR},</if><if test="age != null">age = #{age,jdbcType=INTEGER},</if><if test="cardId != null">card_id = #{cardId,jdbcType=INTEGER},</if></set>where id = #{id,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.Person">update personset name = #{name,jdbcType=VARCHAR},age = #{age,jdbcType=INTEGER},card_id = #{cardId,jdbcType=INTEGER}where id = #{id,jdbcType=INTEGER}</update>
</mapper>

对于上面这么长的文件,最重要的地方是这里

<!-- 一对一:association使用select属性引入另外一条SQL语句 -->
<association property="card" column="card_id"   javaType="top.cairbin.test5.dao.IdCard"
select="top.cairbin.test5.mapper.IdCardMapper.selectByPrimaryKey" />

为了看到效果,我们在mybatis-config.xml里将延迟加载关掉。

<settings><!-- 延迟加载的开关 --><!-- 为了让大家看到关联关系的效果,我们在这里关闭了延迟加载 -->  <setting name="lazyLoadingEnabled" value="false" />  <setting name="aggressiveLazyLoading" value="true"/>  
</settings>

创建UserMapper接口和UserMapper.xml

package top.cairbin.test5.mapper;import top.cairbin.test5.dao.User;public interface UserMapper {int deleteByPrimaryKey(Integer id);int insert(User record);int insertSelective(User record);User selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(User record);int updateByPrimaryKey(User record);
}
<?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="top.cairbin.test5.mapper.UserMapper"><resultMap id="BaseResultMap" type="top.cairbin.test5.dao.User"><id column="id" jdbcType="INTEGER" property="id" /><result column="name" jdbcType="VARCHAR" property="name" /><result column="password" jdbcType="VARCHAR" property="password" /><collection property="ordersList" column="id" ofType="Orders" select="top.cairbin.test5.mapper.OrdersMapper.findOrdersWithUser"></collection></resultMap><sql id="Base_Column_List">id, name, password</sql><select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">select <include refid="Base_Column_List" />from userwhere id = #{id,jdbcType=INTEGER}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">delete from userwhere id = #{id,jdbcType=INTEGER}</delete><insert id="insert" parameterType="top.cairbin.test5.dao.User">insert into user (id, name, password)values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR})</insert><insert id="insertSelective" parameterType="top.cairbin.test5.dao.User">insert into user<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="name != null">name,</if><if test="password != null">password,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="name != null">#{name,jdbcType=VARCHAR},</if><if test="password != null">#{password,jdbcType=VARCHAR},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.User">update user<set><if test="name != null">name = #{name,jdbcType=VARCHAR},</if><if test="password != null">password = #{password,jdbcType=VARCHAR},</if></set>where id = #{id,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.User">update userset name = #{name,jdbcType=VARCHAR},password = #{password,jdbcType=VARCHAR}where id = #{id,jdbcType=INTEGER}</update>
</mapper>

最后OrdersMapperOrdersMapper.xml

package top.cairbin.test5.mapper;import top.cairbin.test5.dao.Orders;public interface OrdersMapper {int deleteByPrimaryKey(Integer id);int insert(Orders record);int insertSelective(Orders record);Orders selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(Orders record);int updateByPrimaryKey(Orders record);
}
<?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="top.cairbin.test5.mapper.OrdersMapper"><resultMap id="BaseResultMap" type="top.cairbin.test5.dao.Orders"><id column="id" jdbcType="INTEGER" property="id" /><result column="number" jdbcType="VARCHAR" property="number" /><result column="user_id" jdbcType="INTEGER" property="userId" /></resultMap><sql id="Base_Column_List">id, number, user_id</sql><select id="findOrdersWithUser" parameterType="Integer" resultMap="BaseResultMap">select * from orders WHERE user_id=#{id}	</select><select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">select <include refid="Base_Column_List" />from orderswhere id = #{id,jdbcType=INTEGER}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">delete from orderswhere id = #{id,jdbcType=INTEGER}</delete><insert id="insert" parameterType="top.cairbin.test5.dao.Orders">insert into orders (id, number, user_id)values (#{id,jdbcType=INTEGER}, #{number,jdbcType=VARCHAR}, #{userId,jdbcType=INTEGER})</insert><insert id="insertSelective" parameterType="top.cairbin.test5.dao.Orders">insert into orders<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="number != null">number,</if><if test="userId != null">user_id,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="number != null">#{number,jdbcType=VARCHAR},</if><if test="userId != null">#{userId,jdbcType=INTEGER},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.Orders">update orders<set><if test="number != null">number = #{number,jdbcType=VARCHAR},</if><if test="userId != null">user_id = #{userId,jdbcType=INTEGER},</if></set>where id = #{id,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.Orders">update ordersset number = #{number,jdbcType=VARCHAR},user_id = #{userId,jdbcType=INTEGER}where id = #{id,jdbcType=INTEGER}</update>
</mapper>

我们编写测试类,在src/test/java下的top.cairbin.test5

PersonTest类来测试一对一的关系

package top.cairbin.test5;import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import top.cairbin.test5.dao.Person;
import top.cairbin.test5.util.*;public class PersonTest {@Testpublic void findPersonByIdTest() {// 1、通过工具类生成SqlSession对象SqlSession session = MyBatisHelper.getSession();// 2.使用MyBatis嵌套查询的方式查询id为1的人的信息Person person = session.selectOne("top.cairbin.test5.mapper." + "PersonMapper.selectByPrimaryKey", 1);// 3、输出查询结果信息System.out.println(person);// 4、关闭SqlSessionsession.close();}//测试一对一(嵌套结果):@Testpublic void findPersonByIdTest2() {// 1、通过工具类生成SqlSession对象SqlSession session = MyBatisHelper.getSession();// 2.使用MyBatis嵌套查询的方式查询id为1的人的信息Person person = session.selectOne("top.cairbin.test5.mapper." + "PersonMapper.findPersonById2", 1);// 3、输出查询结果信息System.out.println(person);// 4、关闭SqlSessionsession.close();}
}

点击运行,两个方法所用时间差距不小。

我们再编写测试类UserTest来测试一对多

package top.cairbin.test5;import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import top.cairbin.test5.dao.User;
import top.cairbin.test5.util.MyBatisHelper;public class UserTest {@Testpublic void findUserTest() {// 1、通过工具类生成SqlSession对象SqlSession session = MyBatisHelper.getSession();// 2、查询id为1的用户信息,注意包名为mapper层的User user = session.selectOne("top.cairbin.test5.mapper."+ "UserMapper.selectByPrimaryKey", 1);// 3、输出查询结果信息System.out.println(user);// 4、关闭SqlSessionsession.close();}}

最后编写OrdersTest来测试多对多

package top.cairbin.test5;import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import top.cairbin.test5.dao.Orders;
import top.cairbin.test5.util.MyBatisHelper;public class OrdersTest {@Testpublic void findOrdersTest(){// 1、通过工具类生成SqlSession对象SqlSession session = MyBatisHelper.getSession();// 2、查询id为1的订单中的商品信息Orders orders = session.selectOne("top.cairbin.test5.mapper."+ "OrdersMapper.selectByPrimaryKey", 1);// 3、输出查询结果信息System.out.println(orders);// 4、关闭SqlSessionsession.close();}
}

总结

在本章节,我们学习了MyBatis的关联映射。此外,你会发现我们写代码不再像以前一样只放在一个包里,而是创建好几个子包分层放置不同的代码,这有利于代码逻辑清晰并且方便维护,这种分层设计已经有一个正式项目的雏形了,当你写完这些东西的时候项目目录应该与我差不多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/294737.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring-boot之shiro安全框架配置使用

shiro架构&#xff08;外部&#xff09; shiro架构(内部) 具体API操作 获取当前的用户对象 Subject currentUser SecurityUtils.getSubject();通过当前用户拿到session Session session currentUser.getSession(); session.setAttribute("someKey", "aValu…

如何在Linux系统运行RStudio Server并实现无公网IP远程访问【内网穿透】

文章目录 推荐 前言1. 安装RStudio Server2. 本地访问3. Linux 安装cpolar4. 配置RStudio server公网访问地址5. 公网远程访问RStudio6. 固定RStudio公网地址 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

惊喜!这一国产数据库认证考试限免了!

今年第一个季度过去了&#xff0c;又到春暖花开时&#xff0c;群里的小伙伴开始躁动不安&#xff0c;焦虑加倍。 有考虑被 cloud 淘汰的&#xff0c;有考虑被共享 emp 的&#xff0c;还有问粗粮 car 能不能当专车开的。 但技术人&#xff0c;更多时间还是在讨论正能量&#xff…

c++的STL(6)-- map和multimap

map和multimap概述 map和multimap中存储的是使用pair对象的键值对。 map和multimap底层也是使用红黑树的数据结构进行实现的。所以&#xff0c;map和multimap内部存储的键值对也是有序的。并且内部数据也是使用链表的形式进行关联。所以其的迭代器和指针&#xff0c;也只能进行…

基于ssm端游账号销售管理系统论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对端游账号销售信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…

认识docker

认识docker 1.镜像和容器2.MySQL镜像命令解读3.docker常用命令4.数据挂载&#xff08;1&#xff09;数据卷&#xff08;2&#xff09;本地目录挂载 5.自定义镜像&#xff08;1&#xff09;Dockerfile 6.容器网络互连7、参考 1.镜像和容器 当我们利用 Docker 安装应用时&#x…

【BlossomRPC】接入注册中心

文章目录 NacosZookeeper自研配置中心 RPC项目 配置中心项目 网关项目 这是BlossomRPC项目的最后一篇文章了&#xff0c;接入完毕注册中心&#xff0c;一个完整的RPC框架就设计完成了。 对于项目对注册中心的整合&#xff0c;其实我们只需要再服务启动的时候将ip/port/servic…

区块链食品溯源案例实现(二)

引言 随着前端界面的完成&#xff0c;我们接下来需要编写后端代码来与区块链网络进行交互。后端将负责处理前端发送的请求&#xff0c;调用智能合约的方法获取食品溯源信息&#xff0c;并将结果返回给前端。 通过前后端的整合&#xff0c;我们可以构建一个食品溯源系统&#xf…

spring boot3登录开发-3(2短信验证登录/注册逻辑实现)

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途 目录 写在前面 上文衔接 内容简介 功能分析 短信验证登录实现 1.创建交互对象 用户短信登录/注册DTO 创建用户登录VO…

Linux(CentOS)安装Redis教程_简单快捷

一、安装依赖 因为redis是用C语言开发的&#xff0c;所以在安装之前需要确定是否安装gcc环境&#xff08;gcc -v&#xff09;&#xff0c;如果没有安转可以执行一下命令进行安装 [rootlocalhost ~]# yum install -y gcc 二、下载安装包 1.在官网先进行下载 官网地址&#x…

【接口测试】Postman(一)--接口测试知识准备

1.0 前言 ​ 应用程序编程接口&#xff08;Application Programming Interface, API&#xff09;是这些年来最流行的技术之一&#xff0c;强大的Web应用程序和领先的移动应用程序都离不开后端强大的API。API技术的应用给系统开发带来了便利&#xff0c;但也对测试人员提出了更…

Ubuntu joystick 测试手柄 xbox

Ubuntu joystick 测试手柄 xbox 测试使用Ubuntu20.04 测试环境在工控机 安装测试 实际测试使用的手柄是北通阿修罗2pro 兼容xbox Ubuntu20.04主机 连接手柄或者无线接收器后查看是否已经检测到&#xff1a; ls /dev/input找到输入中的 js0 即为手柄输入 需要安装joysti…

浅谈 kafka

引言 同事在公司内部分享了关于 kafka 技术一些相关的内容&#xff0c;所以有了这篇文章&#xff1b;部分图片选自网络摘抄&#xff1b; 1 Kafka概述 1.1 定义 Kafka传统定义&#xff1a;kafka是一个分布式的基于发布/订阅模式的消息队列。 Kafka最新定义&#xff1a;kafka…

【讲解下Gitea】

&#x1f308;个人主页:程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

突破编程_前端_JS编程实例(分割窗体组件)

1 开发目标 分隔窗体组件旨在提供灵活的窗体分隔功能&#xff0c;支持横向分割与纵向分隔两种类型&#xff0c;并具备拖拽调整窗体比例的功能&#xff0c;同时提供最小比例设置&#xff0c;以防止窗体被过度缩小&#xff1a; 2 详细需求 2.1 分隔窗体类型 &#xff08;1&…

AI改写文案的注意事项

AI改写文案的注意事项 随着人工智能技术的不断发展&#xff0c;AI改写文案成为了一种新兴的应用场景。通过AI改写文案&#xff0c;可以快速生成大量内容&#xff0c;节省时间和人力成本&#xff0c;但在实际应用中也需要注意一些问题和注意事项。 1. 确保内容原创性 尽管AI改…

个人做量化交易是否可行呢?

考虑个人做量化交易&#xff0c;需要完成两步&#xff1a; 解决3个“什么”的问题&#xff1a;“你要在什么时间&#xff1f;交易什么标的&#xff1f;交易数量是多少&#xff1f;”把你的想法准确地表达出来&#xff0c;告诉交易下单系统 也就是自己形成策略----自己去实现。…

文件操作详解

1.为什么使用文件 目录 1.为什么使用文件 2.什么是文件 2.1程序文件 2.2数据文件 2.3文件名字 3.二进制文件与文本文件 4.文件的打开和关闭 4.1 流 4.2标准流 4.3文件指针 4.4 文件的打开和关闭 fopen fclose 5.文件的顺序读写 5.1文件读取结束原因的判定 5…

mysql 本地电脑服务部署

前提&#xff1a; 下载mysql 新建配置文档 在安装mysql目录新建 my.ini [mysqld] # 设置3306端口 port3306#设置mysql的安装目录 basedirC:\Program Files\MySQL\MySQL Server 8.3 #切记此处一定要用双斜杠\\,单斜杠我这里会出错&#xff0c;不过看别人的教程&#xff0c;有…

走进车厂 | 移远通信以前沿车载技术,照亮智能网联汽车产业创新发展之路

无钥匙自动解锁方便快捷、实时路况导航精准高效、语音指令轻松控制车辆、车载娱乐系统丰富多样……随着智能化、数字化浪潮的不断推进&#xff0c;现如今的汽车出行焕然一新。 正如我们所见&#xff0c;汽车产业正在经历前所未有的变革。物联网、车联网等前沿技术的发展和应用&…