继续前一篇:https://blog.youkuaiyun.com/weixin_44889138/article/details/104731291
概述
- 一对一:在任意一方引入对方主键作为外键。
- 一对多:在“多”的一方,添加“一”的一方的主键作为外键。
- 多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键。
- 创建数据库shopping(我使用的是mariadb)
1. 一对一
如:一个用户只有一个身份证,同时这个身份证也只会对应一个用户。
- 创建数据表
- 创建user表,插入数据
- 创建code表,创建外键,插入数据
- 在eclipse中创建web项目,引入jar包,jar包下载(已经在前一篇有提到)
- 创建包com.xhh.po包,在该包创建持久类:User和Code,如下
User类
package com.xhh.po;
public class User {
private Integer id;
private String account;
private String pwd;
private Code code;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Code getCode() {
return code;
}
public void setCode(Code code) {
this.code = code;
}
@Override
public String toString() {
return "User [id=" + id + ", account=" + account + ", pwd=" + pwd + ", code=" + code + "]";
}
}
Code类
package com.xhh.po;
public class Code {
private Integer id;
private String idCard;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
@Override
public String toString() {
return "Code [id=" + id + ", idCard=" + idCard + "]";
}
}
- 创建com.xhh.mapper包,该包下创建UserMapper.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.xhh.mapper.UserMapper">
<select id="findUserWithCode" parameterType="Map" resultMap="UserWithCodeResult">
select u.*,c.id_card
from user u,code c
where u.id = c.user_id
and account = #{account}
and pwd = #{pwd}
</select>
<resultMap type="User" id="UserWithCodeResult">
<id property="id" column="id"/>
<result property="account" column="account"/>
<result property="pwd" column="pwd" />
<association property="code" javaType="Code">
<id property="id" column="id"/>
<result property="idCard" column="id_card"/>
</association>
</resultMap>
</mapper>
解释:
parameterType="Map"
因为需要传入account和pwd,所以使用Map- 查询代码中可以理解为:利用传入的account和pwd查询出符合这两个的user的id,然后与code中作为外键的字段user_id相等的结果。
resultMap="UserWithCodeResult"
为查询结果后对结果进行映射,(映射到User类),但由于结果中还需要映射到其他类,通过association
,javaType
指定映射到实体对象属性的类型。type="User"
和javaType="Code"
为什么可以直接写类名,而不用写包名?答案在下一步。
- 创建核心配置文件mybatis-config.xml,和其他配置文件,引入Mapper映射文件并定义别名。
<?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"></properties>
<typeAliases>
<!-- 使用这个后就可以在任何地方使用com.xhh.po.IdCard是不必带上完整包名 -->
<package name="com.xhh.po"/>
</typeAliases>
<environments default="mariadb">
<environment id="mariadb">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xhh/mapper/UserMapper.xml"/>
</mappers>
</configuration>
<typeAliases><package name="com.xhh.po"/></typeAliases>
配置这个就可以直接写类名。
db.properties
jdbc.driver=org.mariadb.jdbc.Driver
jdbc.url=jdbc:mariadb://localhost:3306/shopping
jdbc.username=root
jdbc.password=123456
log4j.properties
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.xhh=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
- 创建测试类
package com.xhh.test;
import java.util.HashMap;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import com.xhh.po.User;
import com.xhh.util.MyBatisUtils;
public class DBTest {
@Test
public void findUserWithCode() {
SqlSession sqlSession = MyBatisUtils.getSession();
Map<String,String> map = new HashMap<>();
map.put("account", "48444613");
map.put("pwd", "123456");
User user = sqlSession.selectOne("com.xhh.mapper.UserMapper.findUserWithCode", map);
System.out.println(user.toString());
sqlSession.close();
}
}
结果:
2. 一对多
如:一个用户可以有多个订单,同时多个订单归一个用户所有。
- 创建表orders,并创建外键。
- 在com.xhh.po下创建Orders类,在User中添加属性,生成get,set方法,重新写tostring()
- 快捷键使用(eclipse):使用alt + s 然后选择对应的
idea中使用alt + enter。
熟悉使用快捷键提高速度。。(题外话了哈哈)
Orders
package com.xhh.po;
public class Orders {
private Integer id;
private String number;
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;
}
@Override
public String toString() {
return "Orders [id=" + id + ", number=" + number + "]";
}
}
User
package com.xhh.po;
import java.util.List;
public class User {
private Integer id;
private String account;
private String pwd;
private Code code;
private List<Orders> ordersList;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Code getCode() {
return code;
}
public void setCode(Code code) {
this.code = code;
}
public List<Orders> getOrdersList() {
return ordersList;
}
public void setOrdersList(List<Orders> ordersList) {
this.ordersList = ordersList;
}
@Override
public String toString() {
return "User [id=" + id + ", account=" + account + ", pwd=" + pwd + ", code=" + code + ", ordersList="
+ ordersList + "]";
}
}
- 在com.xhh.mapper中UserMapper.xml中添加
<select id="findUserWithOrders" parameterType="Integer" resultMap="UserWithOrdersResult">
select u.*,o.id as ordersId,o.number
from user u,orders o
where u.id = o.user_id
and u.id = #{id}
</select>
<resultMap type="User" id="UserWithOrdersResult">
<id property="id" column="id"/>
<result property="account" column="account"/>
<result property="pwd" column="pwd"/>
<collection property="ordersList" ofType="Orders">
<id property="id" column="ordersId"/>
<result property="number" column="number"/>
</collection>
</resultMap>
为了简单,这里传入的参数直接用id。
解释:
- 查询代码跟一对一的例子类似,即用户(user)的id与订单(orders)中外键user_id相等,并且传入的参数与用户(user)的id相等。
<collection>
Mybatis通过这个来处理一对多的情况,可以理解为有List使用。里面的ofType与<association>
中的javaType作用相同。- 注意:o.id as ordersId 对这个字段命名,是为了使用时不与user的id区分,因为如果没有设置,查询结果中如图所示:
重命名后id(1)就变成了ordersId,如:
之后通过<id property="id" column="ordersId"/>
映射到Orders中。
- 在测试类中创建测试方法
@Test
public void findUserWithOrders() {
SqlSession sqlSession = MyBatisUtils.getSession();
User user = sqlSession.selectOne("com.xhh.mapper.UserMapper.findUserWithOrders", 1);
System.out.println(user.toString());
sqlSession.close();
}
eclipse运行快捷键:shift + alt + x,出来一个界面后按T ,如果在main方法中则按 J。
结果:
3. 多对多
如:一个订单可以包含多种商品,而一种商品又可以属于多个订单。
多对多通常使用中间表维护。
- 创建商品表和中间表,订单表前面已经创建了。
- 在com.xhh.po中创建Product,Orders类中添加属性。生成get,set,重写tostring
product
package com.xhh.po;
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;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", price=" + price + "]";
}
}
orders
package com.xhh.po;
import java.util.List;
public class Orders {
private Integer id;
private String number;
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;
}
public List<Product> getProductList() {
return productList;
}
public void setProductList(List<Product> productList) {
this.productList = productList;
}
@Override
public String toString() {
return "Orders [id=" + id + ", number=" + number + ", productList=" + productList + "]";
}
}
- 在com.xhh.mapper中创建OrdersMapper.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.xhh.mapper.OrdersMapper">
<select id="findOrdersWithProduct" parameterType="Integer" resultMap="OrdersWithProductResult">
select o.*,p.id as pid,p.name,p.price
from orders o,product p,ordersitem os
where o.id = os.orders_id
and p.id = os.product_id
and o.id = #{id}
</select>
<resultMap type="Orders" id="OrdersWithProductResult">
<id property="id" column="id"/>
<result property="number" column="number"/>
<collection property="productList" ofType="Product">
<id property="id" column="pid"/>
<result property="name" column="name"/>
<result property="price" column="price"/>
</collection>
</resultMap>
</mapper>
跟一对多时类似,就不过多讲解,多多练习吧。
- 在测试类中添加测试方法
@Test
public void findOrdersWithProduct() {
SqlSession sqlSession = MyBatisUtils.getSession();
Orders orders = sqlSession.selectOne("com.xhh.mapper.OrdersMapper.findOrdersWithProduct", 1);
System.out.println(orders.toString());
sqlSession.close();
}
结果:
如果需要查询一个商品被哪些订单包含,则可以反过来查询。
完成。觉得写的好给个赞,点个关注呗。