完成数据库的配置文件编写,实现一对一,一对多,多对多的设计
用户和订单,1:n
用户和地址,1:1
订单和商品,m:n
实现
1,对用户删除,地址和订单都删除
2,对商品删除,删除对应订单中的对应商品
解题:首先呢,我们需要在根据题目要求在数据中建立四张表:用户表,地址表,订单表,商品表。
/*
Navicat MySQL Data Transfer
Source Server : mysql_sport_dev
Source Server Version : 50720
Source Host : localhost:3306
Source Database : javaweb-test04
Target Server Type : MYSQL
Target Server Version : 50720
File Encoding : 65001
Date: 2018-11-07 21:55:42
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for addresslist
-- ----------------------------
DROP TABLE IF EXISTS `addresslist`;
CREATE TABLE `addresslist` (
`addressId` int(11) NOT NULL AUTO_INCREMENT,
`addressName` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`userId` int(11) NOT NULL,
PRIMARY KEY (`addressId`),
KEY `addresslist_ibfk_1` (`userId`),
CONSTRAINT `addresslist_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `userlist` (`userId`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- ----------------------------
-- Table structure for goodslist
-- ----------------------------
DROP TABLE IF EXISTS `goodslist`;
CREATE TABLE `goodslist` (
`goodsid` int(11) NOT NULL AUTO_INCREMENT,
`goodsname` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`goodsprice` int(11) DEFAULT NULL,
PRIMARY KEY (`goodsid`),
KEY `goodsname` (`goodsname`),
KEY `goodsprice` (`goodsprice`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- ----------------------------
-- Table structure for orderlist
-- ----------------------------
DROP TABLE IF EXISTS `orderlist`;
CREATE TABLE `orderlist` (
`orderid` int(11) NOT NULL AUTO_INCREMENT,
`userId` int(11) DEFAULT NULL,
`goodsnumber` int(11) DEFAULT NULL,
`sumprice` int(11) DEFAULT NULL,
PRIMARY KEY (`orderid`),
KEY `orderlist_ibfk_1` (`userId`),
CONSTRAINT `orderlist_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `userlist` (`userId`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-- ----------------------------
-- Table structure for order_goods
-- ----------------------------
DROP TABLE IF EXISTS `order_goods`;
CREATE TABLE `order_goods` (
`goodsid` int(11) NOT NULL,
`orderid` int(11) NOT NULL,
PRIMARY KEY (`goodsid`,`orderid`),
KEY `order_goods_ibfk_2` (`orderid`),
CONSTRAINT `order_goods_ibfk_1` FOREIGN KEY (`goodsid`) REFERENCES `goodslist` (`goodsid`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `order_goods_ibfk_2` FOREIGN KEY (`orderid`) REFERENCES `orderlist` (`orderid`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for userlist
-- ----------------------------
DROP TABLE IF EXISTS `userlist`;
CREATE TABLE `userlist` (
`userId` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`psw` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`userId`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
接下来,我们来分别完成1:1,1:n,m:n(文件目录结构如下)
1. 1:1,一对一其实可以看做是特殊的一对多,即添加属性unique="true"即可。
首先新建持久化类Address和User。实现一对一映射时,需要在双方的持久化类中分别添加对方类对象。自己的属性和setter和getter方法我就不多说了。
//Address.java
package com.entity;
public class Address {
private int addressId;
private String addressName;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public int getAddressId() {
return addressId;
}
public void setAddressId(int addressId) {
this.addressId = addressId;
}
public String getAddressName() {
return addressName;
}
public void setAddressName(String addressName) {
this.addressName = addressName;
}
public Address() {
}
public Address(int addressId, String addressName) {
this.addressId = addressId;
this.addressName = addressName;
}
public Address(String addressName) {
this.addressName = addressName;
}
}
//User.java
package com.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class User implements Serializable {
private int userId;
private String username;
private String psw;
//一对多时,在一方定义一个多方的集合
private Set<Order> order = new HashSet<Order>();
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPsw() {
return psw;
}
public void setPsw(String psw) {
this.psw = psw;
}
public Set<Order> getOrder() {
return order;
}
public void setOrder(Set<Order> order) {
this.order = order;
}
public User() {
}
public User(int userId, String username, String psw, Set<Order> order) {
this.userId = userId;
this.username = username;
this.psw = psw;
this.order = order;
}
public User(String username) {
this.username = username;
}
}
接着,创建映射文件:在映射文件中实现了两个持久化类对应的两张数据库表之间的关联关系,即一对一。
//Address.hbm.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.entity.Address" table="addresslist">
<id name="addressId" column="addressId" type="java.lang.Integer">
<!--设置主键为自增模式-->
<generator class="increment"></generator>
</id>
<property name="addressName" type="java.lang.String">
<column name="addressName" length="255" not-null="true"></column>
</property>
<many-to-one class="com.entity.User" unique="true" name="user"
column="userId" cascade="all"></many-to-one>
</class>
</hibernate-mapping>
//User.hbm.xml(下面的代码中还包含1:n的部分)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.entity.User" table="userlist">
<id name="userId" column="userId" type="java.lang.Integer">
<!--设置主键为自增模式-->
<generator class="increment"></generator>
</id>
<property name="username" type="java.lang.String">
<column name="username" length="255" not-null="true"></column>
</property>
<property name="psw" type="java.lang.String">
<column name="psw" length="255" ></column>
</property>
<set name="order" table="orderlist" inverse="false" cascade="all">
<key column="userId"></key>
<one-to-many class="com.entity.Order"/>
</set>
<one-to-one class="com.entity.Address" name="address"></one-to-one>
</class>
</hibernate-mapping>
映射文件写好后,记得在hibernate.cfg.xml中添加这两个xml文件,后面新建的xml也需要进行添加。
2. 1:n
同1:1,需要创建对应的持久化类和映射文件。这里是User.java和Order.java
//User.java,就是上面的那个,在该类中需要定义多方Order的一个集合。
//Order.java,在1:n关系中,作为多方的Order,只需要定义自己的属性。代码中出现的集合是给后面m:n关系用的。
package com.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Order implements Serializable {
private int orderid;
private int goodsnumber;
private int sumprice;
//添加一个货物的集合
private Set<Goods> goods = new HashSet<Goods>();
public Set<Goods> getGoods() {
return goods;
}
public void setGoods(Set<Goods> goods) {
this.goods = goods;
}
public int getOrderid() {
return orderid;
}
public void setOrderid(int orderid) {
this.orderid = orderid;
}
public int getGoodsnumber() {
return goodsnumber;
}
public void setGoodsnumber(int goodsnumber) {
this.goodsnumber = goodsnumber;
}
public int getSumprice() {
return sumprice;
}
public void setSumprice(int sumprice) {
this.sumprice = sumprice;
}
public Order() {
}
public Order(int orderid, int goodsnumber, int sumprice) {
this.orderid = orderid;
this.goodsnumber = goodsnumber;
this.sumprice = sumprice;
}
public Order(int goodsnumber, int sumprice) {
this.goodsnumber = goodsnumber;
this.sumprice = sumprice;
}
}
接着写映射文件:Order.hbm.xml和User.hbm.xml(前面写过了)
//Order.hbm.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.entity.Order" table="orderlist">
<id name="orderid" column="orderid" type="java.lang.Integer">
<!--设置主键为自增模式-->
<generator class="increment"></generator>
</id>
<property name="goodsnumber" type="java.lang.Integer">
<column name="goodsnumber" length="11" not-null="true"></column>
</property>
<property name="sumprice" type="java.lang.Integer">
<column name="sumprice" length="11" not-null="true"></column>
</property>
<!--多对多映射关系-->
<!--inverse等于true表示多对多关系的维护由对方完成,多对多联系时必须有一方的inverse是true,被add的那一方的xml里写inverse="true",表示有另一方来维护。在add的xml里写的是cascade="all"表示级联所有操作-->
<set name="goods" table="order_goods" cascade="all">
<key column="orderid"></key>
<many-to-many class="com.entity.Goods" column="goodsid"></many-to-many>
</set>
</class>
</hibernate-mapping>
//User.hbm.xml前面写过了,需要定义one-to-many
3. m:n(算是三个关系里最难的一个了吧,个人觉得)
同上,需要建立持久化类和映射文件
//Order.java(前面写过了,在该类中定义了另一个类的集合)
package com.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Goods implements Serializable {
private int goodsid;
private String goodsname;
private int goodsprice;
//添加一个订单的集合
private Set<Order> orders = new HashSet<Order>();
public Goods() {
}
public Goods(int goodsid, String goodsname, int goodsprice, Set<Order> orders) {
this.goodsid = goodsid;
this.goodsname = goodsname;
this.goodsprice = goodsprice;
this.orders = orders;
}
public int getGoodsid() {
return goodsid;
}
public void setGoodsid(int goodsid) {
this.goodsid = goodsid;
}
public String getGoodsname() {
return goodsname;
}
public void setGoodsname(String goodsname) {
this.goodsname = goodsname;
}
public int getGoodsprice() {
return goodsprice;
}
public void setGoodsprice(int goodsprice) {
this.goodsprice = goodsprice;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
public Goods(String goodsname, int goodsprice) {
this.goodsname = goodsname;
this.goodsprice = goodsprice;
}
}
创建映射文件:
//Order.hbm.xml(前面写过了)
//Goods.hbm.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.entity.Goods" table="goodslist">
<id name="goodsid" column="goodsid" type="java.lang.Integer">
<!--设置主键为自增模式-->
<generator class="increment"></generator>
</id>
<property name="goodsname" type="java.lang.String">
<column name="goodsname" length="255" not-null="true"></column>
</property>
<property name="goodsprice" type="java.lang.Integer">
<column name="goodsprice" length="11" not-null="true"></column>
</property>
<!--set中的name属性是集合名称的意思,table对应的是连接练个多对多的表的关系表-->
<set name="orders" table="order_goods" inverse="false" cascade="all" >
<key column="goodsid"></key>
<many-to-many class="com.entity.Order" column="orderid"></many-to-many>
</set>
</class>
</hibernate-mapping>
在多对多的映射文件中,我们需要在主控方和被控方的xml里设置many-to-many,具体写法如上。需要注意的是:多对多关系中的任意一方,必须要有inverse属性,inverse="true"表示由对方来维护两个表之间的关系,可以同时设置为inverse="false".不能同时设置为="true",cascade是级联操作的意思,cascade="all"表示该表中的值发生变化后,与该表相关的所有内容都会发生级联操作从而发生变化。
测试类:
package com.entity;
import com.utils.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class test_OneToManyToMany {
public static void main(String[] args){
User user = new User("王某");
Address address = new Address("成都理工大学");
Order order01 = new Order(1,11);
Order order02 = new Order(3,22);
Goods goods01 = new Goods("小饼干",5);
Goods goods02 = new Goods("小鸡腿",3);
//将用户加入地址中
address.setUser(user);
//订单1和订单2中都有小鸡腿
goods01.getOrders().add(order01);
goods01.getOrders().add(order02);
//小饼干只在订单二中
goods02.getOrders().add(order02);
user.getOrder().add(order01);
user.getOrder().add(order02);
Session session = HibernateUtils.getSession();
Transaction tx = session.beginTransaction();
session.save(address);
session.save(user);
session.save(goods01);
session.save(goods02);
tx.commit();
HibernateUtils.closeSession(session);
}
}
在做这道题的时候,卡壳的地方有:
1.没有理解inverse的意思,inverse为false的那一方是两个表关系的维护方,因此在数据库中插入的时候提交的维护方的对象,然后会通过cascade级联操作在数据库中插入被维护方的数据。比如这道题中,多对多关系中的维护方是商品,因此在测试类中是王商品对象中添加订单
//订单1和订单2中都有小鸡腿
goods01.getOrders().add(order01);
goods01.getOrders().add(order02);
//小饼干只在订单二中
goods02.getOrders().add(order02);
user.getOrder().add(order01);
user.getOrder().add(order02);
Session session = HibernateUtils.getSession();
Transaction tx = session.beginTransaction();
session.save(goods01);
session.save(goods02);
tx.commit();
2.如何实现三个表之间的一对多对多?
拿本题举例,如何实现删除用户,就能实现删除订单和订单与商品中间的关系表?
答:用一对多中的一方来控制全局即可 ,也就是一方控制多方,多方再去控制另一个多方,就能实现上述操作了。前面写的测试类就用到了这种方法。记得设置cascade