【JavaEE学习笔记】Hibernate_06_注解开发,getCurrentSession(),映射关系
2018-01-22 23:13
736 查看
Hibernate_06
A.注解
1.概述
每个持久化POJO类都是一个实体Bean
通过在类的定义中使用@Entity注解来进行声明
目前定义属性对应的列时有两种定义方法
a.定义在属性上
b.定义在get方法上
两种方法是等价的,目前没有选择标准,但一个类中只能使用一种方法
2.常用字段属性
3.常用注解
4.使用步骤
导入hibernate,mysql驱动
建立UserBean
package org.wpf.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
// 定义为实体类,数据库中的表名为t_users
@Entity(name = "t_users")
public class UserBean implements Serializable {
private static final long serialVersionUID = -5771488248839932252L;
// 主键
@Id
// 定义标识符生成策略
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 长度为20,不能为空,唯一
@Column(length = 20, nullable = false, unique = true)
private String username;
// 长度为20,不能为空
@Column(length = 20, nullable = false)
private String password;
// 获取日期
@Temporal(TemporalType.DATE)
// 设置该列值默认为系统当前时间
@Column(columnDefinition = "timestamp default current_timestamp")
private Date birth;
// 宽度为8,精度为2
@Column(precision = 8, scale = 2)
private Double salary;
// 默认值为1
@Column(columnDefinition = "boolean default 1")
private boolean sex;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
配置hibernate.cfg.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 此处映射为javaBean -->
<mapping class="org.wpf.entity.UserBean" />
</session-factory>
</hibernate-configuration>
测试类
package org.wpf.entity;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
public class Demo01 {
public static void main(String[] args) {
ServiceRegistry sr = new StandardServiceRegistryBuilder().configure().build();
SessionFactory fac = new MetadataSources(sr).buildMetadata().buildSessionFactory();
Session session = fac.openSession();
Transaction tx = session.beginTransaction();
UserBean u1 = new UserBean();
u1.setUsername("zhangsan");
u1.setPassword("123456");
session.save(u1);
tx.commit();
session.close();
fac.close();
}
}
查看控制台
查看数据库表
查看数据
5.annotation主键生成策略
一般情况下都是使用annoation的标准注解
标准的annotation方式的主键生成策略:auto table identity squence
table使用表保存id(创建一张专门保存id的表,记录对应的表的对应最大id值)
@javax.persistence.TableGenerator(
name="EMP_GEN",生成器的名称
table="GENERATOR_TABLE",额外表的名称
pkColumnName="key",额外表的主键列的名称
valueColumnName="hi",额外表的id值对应列的名称
pkColumnValue="EMP",额外表的主键列的值
allocationSize=20,额外表的id增长的步长值
)
package org.wpf.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
// 定义为实体类,数据库中的表名为t_users
@Entity(name = "t_users")
public class UserBean implements Serializable {
private static final long serialVersionUID = -5771488248839932252L;
// 主键生成策略
@TableGenerator(name = "EMP_GEN",
table = "GENERATOR_TABLE",
pkColumnName = "key1",
valueColumnName = "hi",
pkColumnValue = "abc",
allocationSize = 20)
// 主键
@Id
// 定义标识符生成策略
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 长度为20,不能为空,唯一
@Column(length = 20, nullable = false, unique = true)
private String username;
// 长度为20,不能为空
@Column(length = 20, nullable = false)
private String password;
// 获取日期
@Temporal(TemporalType.DATE)
// 设置该列值默认为系统当前时间
@Column(columnDefinition = "timestamp default current_timestamp")
private Date birth;
// 宽度为8,精度为2
@Column(precision = 8, scale = 2)
private Double salary;
// 默认值为1
@Column(columnDefinition = "boolean default 1")
private boolean sex;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
B.getCurrentSession
1.openSession()和getCurrentSession()区别
openSession()每次都会新建一个Session
getCurrentSession首先从上下文中查找是否有session,有则获取,无则新建
getCurrentSession需要有对应的事物支持,当事务结束时会自动关闭session
openSession必须手动关闭
getCurrentSession的使用需要有额外配置
<property name="hibernate.current_session_context_class">thread</property>
2.引入getCurrentSession()后的工具类
package org.wpf.util;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
public class HibernateSessionFactory {
private static SessionFactory sessionFactory;
static {
buildSessionFactory();
}
// 私有构造
private HibernateSessionFactory() {
}
// 获取SessionFactory
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
// 创建session工厂
private static void buildSessionFactory() throws HibernateException {
// 如果没有
if (sessionFactory == null) {
ServiceRegistry sr = new StandardServiceRegistryBuilder().configure().build();
sessionFactory = new MetadataSources(sr).buildMetadata().buildSessionFactory();
}
}
}
3.过滤器
package org.wpf.fliter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.wpf.util.HibernateSessionFactory;
public class OpenSessionInViewFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
try {
// 开启事物
HibernateSessionFactory.getSessionFactory().getCurrentSession().beginTransaction();
// 放行
arg2.doFilter(arg0, arg1);
// 提交事物
HibernateSessionFactory.getSessionFactory().getCurrentSession().getTransaction().commit();
} catch (Exception e) {
// 回滚
HibernateSessionFactory.getSessionFactory().getCurrentSession().getTransaction().rollback();
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
C.映射关系
1.常见映射关系
一对一
一对多或多对一
多对多
关联关系实际开发中可以分为单向关联和双相关联
2.一对多查询
一对多或多对一的关联在实际开发中用的比较多
一个简单的例子就是客户与订单的关系
一个客户可能发出多个订单,而每个订单只属于一个客户
这样,如果从客户指向订单,这种关系就属于一对多的关系
在关系数据库中,只有存在外键参照关系,而且总是由many方参照one方
因此,在关系数据库中,实际支持多对一或一对一的单项关联即可
3.Oracle中的SQL可以分为4大类
DDL数据定义语言 create drop alter truncate
DML数据操纵语言 insert update delete select
DCL数据控制语言 grant revoke [with admin option 和 with grant option]
TCL事物控制语言 commit rollback savepoint
4.截断操作 truncate table t_users
truncate属于DDL,没有事物的概念,删除后没有办法恢复
不会记录日志信息,所以删除大量数据时,执行效率远高于delete from
5.定义一对多
一方Customer
package org.wpf.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Customer implements Serializable {
private static final long serialVersionUID = 4313768320545350900L;
private Long id;
private String name;
// 这是类中表示1对多关联的方式,表示一个Customer中包含了多个Order
private Set<Order> orders = new HashSet<>(0);
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", orders=" + orders + "]";
}
}
Customer.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.wpf.entity.Customer" table="t_customer">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="20" not-null="true" />
</property>
<set name="orders" inverse="true" cascade="all">
<key>
<column name="customer_id" not-null="true" />
</key>
<one-to-many class="org.wpf.entity.Order" />
</set>
</class>
</hibernate-mapping>
多方Order
package org.wpf.entity;
import java.io.Serializable;
import java.util.Date;
public class Order implements Serializable {
private static final long serialVersionUID = 5875230206918806994L;
private Long id;
private Customer customer;
private Date oDate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Date getoDate() {
return oDate;
}
public void setoDate(Date oDate) {
this.oDate = oDate;
}
@Override
public String toString() {
return "Order [id=" + id + ", customer=" + customer + ", oDate=" + oDate + "]";
}
}
Order.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.wpf.entity.Order" table="T_ORDER">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="identity" />
</id>
<many-to-one name="customer" class="org.wpf.entity.Customer"
fetch="select">
<column name="customer_id" not-null="true" />
</many-to-one>
<property name="oDate" type="java.util.Date">
<column name="odate" length="19" not-null="true" />
</property>
</class>
</hibernate-mapping>
在配置文件中添加映射
<mapping resource="org/wpf/entity/Customer.hbm.xml"/>
<mapping resource="org/wpf/entity/Order.hbm.xml"/>测试类
package org.wpf.entity;
import java.util.Date;
import org.hibernate.Session;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.wpf.util.HibernateSessionFactory;
class Test01 {
@BeforeEach
void setUp() throws Exception {
HibernateSessionFactory.getSessionFactory().getCurrentSession().beginTransaction();
}
@AfterEach
void tearDown() throws Exception {
HibernateSessionFactory.getSessionFactory().getCurrentSession().getTransaction().commit();
}
@Test
void test() {
// 级联需要互相通知
Customer c1 = new Customer();
c1.setName("Tom");
Order o1 = new Order();
o1.setoDate(new Date());
Order o2 = new Order();
o2.setoDate(new Date());
// 相互通知
c1.getOrders().add(o1);
o1.setCustomer(c1);
c1.getOrders().add(o2);
o2.setCustomer(c1);
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
session.save(c1);
}
}
控制台信息
Hibernate:
create table t_customer (
ID bigint not null auto_increment,
NAME varchar(20) not null,
primary key (ID)
) engine=InnoDB
Hibernate:
create table T_ORDER (
ID bigint not null auto_increment,
customer_id bigint not null,
odate datetime not null,
primary key (ID)
) engine=InnoDB
Hibernate:
alter table T_ORDER
add constraint FKfiait2tmbi08bkn450b9c5i54
foreign key (customer_id)
references t_customer (ID)
Hibernate:
insert
into
t_customer
(NAME)
values
(?)
Hibernate:
insert
into
T_ORDER
(customer_id, odate)
values
(?, ?)
Hibernate:
insert
into
T_ORDER
(customer_id, odate)
values
(?, ?)运行结果
6.inverse和cascade
inverse的真正作用就是指定由哪一方来维护之间的关联关系
当一方中制订了inverse=false默认,那么那一方就有责任负责之间的关联关系
就是hibernate如何生成sql来维护关联的记录
区别:
Inverse负责控制关系,默认为false,也就是两端都能控制
但造成一些问题,更新时会因为两端都控制,于是重复更新
一般有一端要设为true
cascade负责控制关联对象的级联操作,包括更新,删除等
也就是说对一个对象进行更新,删除时,其他对象也受影响
那么跟他是多对一的关系的对象也全部被删除
7.其他属性
<set>元素包括以下属性
name:设定待映射的持久化类的属性名
cascade:当取值为save_update时,表示级联保存和更新
<set>元素还可以包括<key>和<one-to-many>两个子元素
<key>元素设定与所关联的持久化类对应表的外键
<one-to-many>元素设定所关联的持久化类
<many-to-one>元素建立了订单和客户表的外键之间的映射
name:设置待映射的持久化类的属性名
column:设定和持久化类的属性对应的表的外键
class:设定持久化类的属性类型
not-null:如果为true,表示客户属性不允许为空
fetech="select":抓取策略的设置,表示获取订单后如何获取对应的客户信息
将fetch修改为join,表示获取客户信息时不是采用发送额外的select语句进行获取,而是采用inner join的方式直接查询客户信息,不会产生额外的SQL语句,采用这样的方式查询效率会略高于发送额外查询的方式
8.注解定义的方式
customer
package org.wpf.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
@Entity(name = "t_customer")
public class Customer implements Serializable {
private static final long serialVersionUID = 4313768320545350900L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 32, nullable = false)
private String name;
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
@OrderBy("id desc")
private Set<Order> orders = new HashSet<>(0);
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", orders=" + orders + "]";
}
}
order
package org.wpf.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity(name = "t_order")
public class Order implements Serializable {
private static final long serialVersionUID = 5875230206918806994L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "all_price", precision = 8, scale = 2)
private Double allPrice;
@ManyToOne(optional = false)
@JoinColumn(name = "customer_id")
private Customer customer;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Double getAllPrice() {
return allPrice;
}
public void setAllPrice(Double allPrice) {
this.allPrice = allPrice;
}
@Override
public String toString() {
return "Order [id=" + id + ", allPrice=" + allPrice + ", customer=" + customer + "]";
}
}
设置配置文件
<mapping class="org.wpf.entity.Customer"/>
<mapping class="org.wpf.entity.Order"/>运行结果
Hibernate:
create table t_customer (
id bigint not null auto_increment,
name varchar(32) not null,
primary key (id)
) engine=InnoDB
Hibernate:
create table t_order (
id bigint not null auto_increment,
all_price double precision,
customer_id bigint not null,
primary key (id)
) engine=InnoDB
Hibernate:
alter table t_order
add constraint FKesy3n2gc3fa0s3trrk3tvyv9a
foreign key (customer_id)
references t_customer (id)
Hibernate:
insert
into
t_customer
(name)
values
(?)
Hibernate:
insert
into
t_order
(all_price, customer_id)
values
(?, ?)
Hibernate:
insert
into
t_order
(all_price, customer_id)
values
(?, ?)
9.一对一
实现方式:
共享主键和唯一外键
10.共享主键
既是主键,又是外键,主控方和受控方
a.xml
Person主控方
package org.wpf.entity;
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = -6446631496216328660L;
private Long id;
private String name;
private Card card;
public Person() {
super();
}
public Person(Long id, String name, Card card) {
super();
this.id = id;
this.name = name;
this.card = card;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
}
Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 22:27:49 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Person" table="t_person">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="10" not-null="true" />
</property>
<one-to-one name="card" class="org.wpf.entity.Card"
cascade="all"></one-to-one>
</class>
</hibernate-mapping>
Card受控方
package org.wpf.entity;
import java.io.Serializable;
public class Card implements Serializable {
private static final long serialVersionUID = 7490343597638703173L;
private Long id;
private Person person;
private String city;
public Card() {
super();
}
public Card(Long id, Person person, String city) {
super();
this.id = id;
this.person = person;
this.city = city;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
Card.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 22:27:49 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Card" table="t_card" catalog="test">
<id name="id" type="java.lang.Long">
<column name="ID" />
<!-- 表明根据对方的主键来生成自己的主键,自己并不能独立生成主键 ,这里表示身份证的主键值是从它属性person的id值中获取的 -->
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<!-- constrained="true"表示当前类是受控方,受Person的控制 -->
<one-to-one name="person" class="org.wpf.entity.Person"
constrained="true" />
<property name="city" type="java.lang.String">
<column name="CITY" length="32" />
</property>
</class>
</hibernate-mapping>
b.注解
Husband主控方
package org.wpf.entity;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
@Entity(name = "t_husband") // 主控方
public class Husband implements Serializable {
private static final long serialVersionUID = 7204300104344481060L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 20, nullable = false)
private String name;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "husband")
private Wife wife;
public Husband() {
super();
}
public Husband(Long id, String name, Wife wife) {
super();
this.id = id;
this.name = name;
this.wife = wife;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Wife getWife() {
return wife;
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
Wife受控方
package org.wpf.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
@Entity(name = "t_wife")
public class Wife implements Serializable {
private static final long serialVersionUID = -6685649713801290134L;
@Id
@GenericGenerator(name = "ff1", strategy = "foreign", parameters = {
@Parameter(name = "property", value = "husband") })
@GeneratedValue(generator = "ff1")
private Long id;
@Column(length = 32)
private String name;
@OneToOne(orphanRemoval = true)
@PrimaryKeyJoinColumn
private Husband husband;
public Wife() {
super();
}
public Wife(Long id, String name, Husband husband) {
super();
this.id = id;
this.name = name;
this.husband = husband;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Husband getHusband() {
return husband;
}
public void setHusband(Husband husband) {
this.husband = husband;
}
}
@GenericGenerator(name = "foreignKey"
生成器名称,供GeneratedValue中进行调用
strategy = "foreign" 使用hibernate的外键策略
parameters = @Parameter(value = "article参数值",name = "property参数名称"))//指定成员属性中的article所在类的主键为本类的主键,这里的参数属性name必须为"property"
@GeneratedValue(generator = "foreignKey")//使用上述定义的id生成器
11.唯一外键的关联实现方式
a.xml(bean和上面的一样,省略)
Husband.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 22:47:11 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Husband" table="HUSBAND">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="20" not-null="true" />
</property>
<one-to-one name="wife" class="org.wpf.entity.Wife"
cascade="all" property-ref="husband" />
</class>
</hibernate-mapping>
Wife.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 22:47:11 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Wife" table="WIFE">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="20" not-null="true" />
</property>
<many-to-one name="husband" class="org.wpf.entity.Husband"
unique="true" column="husband_id" />
</class>
</hibernate-mapping>
b.注解
Person
package org.wpf.entity;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
@Entity(name = "t1_person")
public class Person implements Serializable {
private static final long serialVersionUID = -6446631496216328660L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 32)
private String name;
@OneToOne(mappedBy = "person", cascade = CascadeType.ALL)
private Card card;
public Person() {
super();
}
public Person(Long id, String name, Card card) {
super();
this.id = id;
this.name = name;
this.card = card;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
}
Card
package org.wpf.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
@Entity(name = "t1_person")
public class Card implements Serializable {
private static final long serialVersionUID = -5345063387498725762L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 32)
private String name;
@OneToOne(optional = false)
@JoinColumn(name = "person_id")
private Person person;
public Card() {
super();
}
public Card(Long id, String name, Person person) {
super();
this.id = id;
this.name = name;
this.person = person;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
12.多对多关联
在关系型数据库中是不能直接表达多对多关联,必须引入一个中间表
注意中间表表中不能包含非键列。中间表没有对应的映射文件
Student
package org.wpf.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Student implements Serializable {
private static final long serialVersionUID = 7767264496828265124L;
private Long id;
private String name;
private Set courses = new HashSet(0);
public Student() {
super();
}
public Student(Long id, String name, Set courses) {
super();
this.id = id;
this.name = name;
this.courses = courses;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getCourses() {
return courses;
}
public void setCourses(Set courses) {
this.courses = courses;
}
}
Student.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.wpf.entity.Student" table="t_student">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="Name" length="20" not-null="true" />
</property>
<set name="courses" table="t_choice" cascade="all">
<key>
<column name="Student_id" not-null="true" />
</key>
<many-to-many entity-name="org.wpf.entity.Course">
<column name="Course_id" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
Course
package org.wpf.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Course implements Serializable {
private static final long serialVersionUID = -2850799906496654565L;
private Long id;
private String title;
private Set students = new HashSet(0);
public Course() {
super();
}
public Course(Long id, String title, Set students) {
super();
this.id = id;
this.title = title;
this.students = students;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Set getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
}
Course.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 23:00:29 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Course" table="t_course">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="title" type="java.lang.String">
<column name="TITLE" length="50" not-null="true" />
</property>
<set name="students" inverse="true" table="t_choice">
<key>
<column name="Course_id" not-null="true" />
</key>
<many-to-many entity-name="org.wpf.entity.Student">
<column name="Student_id" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
控制台信息
Hibernate:
create table t_choice (
Course_id bigint not null,
Student_id bigint not null,
primary key (Student_id, Course_id)
) engine=InnoDB
Hibernate:
create table t_course (
ID bigint not null auto_increment,
TITLE varchar(50) not null,
primary key (ID)
) engine=InnoDB
Hibernate:
create table t_student (
ID bigint not null auto_increment,
Name varchar(20) not null,
primary key (ID)
) engine=InnoDB
Hibernate:
alter table t_choice
add constraint FK93ey2xm8fobois7ev90lrrefd
foreign key (Student_id)
references t_student (ID)
Hibernate:
alter table t_choice
add constraint FKjd0jtvxffqm4e7yi50ed1frju
foreign key (Course_id)
references t_course (ID)查看数据库
13.Hibernate注解规范的文档中提供了三种方法
将组件类注解为@Embeddable,并将组件的属性注解为@Id
将组件的属性注解为@ EmbeddedId
@Embeddable
public class UserId implements Serializable {
@Id
UserId uid;
}将类注解为@IdClass,并将该实体中所有主键属性注解为@Id,最常用的方法
需要根据所有的主键属性,建立一个主键类
主键类必须实现序列化接口(Serializable)
主键类必须有默认的public无参数的构造方法
主键类必须覆盖equals和hashCode方法
@IdClass(IPMapKey.class)
public class IPMap {
@Id @Column(name="IP")
private String ip;
@Id @Column(name="ExamPlaceId")
private String examPlaceId;
}
A.注解
1.概述
每个持久化POJO类都是一个实体Bean
通过在类的定义中使用@Entity注解来进行声明
目前定义属性对应的列时有两种定义方法
a.定义在属性上
b.定义在get方法上
两种方法是等价的,目前没有选择标准,但一个类中只能使用一种方法
2.常用字段属性
name="cloumnName" | 当前属性对应的列名,如果列名称和属性名称一致,可以省略 |
boolean unique() default false | 是否在该列上设置唯一约束,一般开发阶段不建议定义大量的约束 |
boolean nullable() default true | 设置对应的列是否允许为空 |
boolean insertable() default true | 该列是否作为生成insert语句的一个列 |
boolean updatable() default true | 该列是否作为生成update语句的一个列 |
String columnDefinition() default | 直接定义对应列的配置,但是会导致跨数据库平台性的丢失 |
String table() default "" | 定义对应的表 default是主表 |
int length() default 255 | 针对字串类型的列定义长度 |
int percision() default 0 | 针对数字类型的列定义数值精度 |
int scale() default 0 | 针对数值类型的列定义数值精度,这里定义小数位数 |
Entity | 定义实体类 |
Column | 定义属性 |
Temporal | 用于给日期类型定义获时的精度:Date获取日期,Time获取时间,Timestamp获取日期时间 |
Transient,Basic | 所有非static非transient属性都可以被持久化,除非用transient注解,默认都为Basic |
Id | 可以将某个属性定义为主键 |
GenerateValue | 定义该标识符的生成策略 |
AUTO | 可以是identity column,squence或者table类型,取决于不同底层的数据库 |
导入hibernate,mysql驱动
建立UserBean
package org.wpf.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
// 定义为实体类,数据库中的表名为t_users
@Entity(name = "t_users")
public class UserBean implements Serializable {
private static final long serialVersionUID = -5771488248839932252L;
// 主键
@Id
// 定义标识符生成策略
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 长度为20,不能为空,唯一
@Column(length = 20, nullable = false, unique = true)
private String username;
// 长度为20,不能为空
@Column(length = 20, nullable = false)
private String password;
// 获取日期
@Temporal(TemporalType.DATE)
// 设置该列值默认为系统当前时间
@Column(columnDefinition = "timestamp default current_timestamp")
private Date birth;
// 宽度为8,精度为2
@Column(precision = 8, scale = 2)
private Double salary;
// 默认值为1
@Column(columnDefinition = "boolean default 1")
private boolean sex;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
配置hibernate.cfg.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 此处映射为javaBean -->
<mapping class="org.wpf.entity.UserBean" />
</session-factory>
</hibernate-configuration>
测试类
package org.wpf.entity;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
public class Demo01 {
public static void main(String[] args) {
ServiceRegistry sr = new StandardServiceRegistryBuilder().configure().build();
SessionFactory fac = new MetadataSources(sr).buildMetadata().buildSessionFactory();
Session session = fac.openSession();
Transaction tx = session.beginTransaction();
UserBean u1 = new UserBean();
u1.setUsername("zhangsan");
u1.setPassword("123456");
session.save(u1);
tx.commit();
session.close();
fac.close();
}
}
查看控制台
查看数据库表
查看数据
5.annotation主键生成策略
一般情况下都是使用annoation的标准注解
标准的annotation方式的主键生成策略:auto table identity squence
table使用表保存id(创建一张专门保存id的表,记录对应的表的对应最大id值)
@javax.persistence.TableGenerator(
name="EMP_GEN",生成器的名称
table="GENERATOR_TABLE",额外表的名称
pkColumnName="key",额外表的主键列的名称
valueColumnName="hi",额外表的id值对应列的名称
pkColumnValue="EMP",额外表的主键列的值
allocationSize=20,额外表的id增长的步长值
)
package org.wpf.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
// 定义为实体类,数据库中的表名为t_users
@Entity(name = "t_users")
public class UserBean implements Serializable {
private static final long serialVersionUID = -5771488248839932252L;
// 主键生成策略
@TableGenerator(name = "EMP_GEN",
table = "GENERATOR_TABLE",
pkColumnName = "key1",
valueColumnName = "hi",
pkColumnValue = "abc",
allocationSize = 20)
// 主键
@Id
// 定义标识符生成策略
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 长度为20,不能为空,唯一
@Column(length = 20, nullable = false, unique = true)
private String username;
// 长度为20,不能为空
@Column(length = 20, nullable = false)
private String password;
// 获取日期
@Temporal(TemporalType.DATE)
// 设置该列值默认为系统当前时间
@Column(columnDefinition = "timestamp default current_timestamp")
private Date birth;
// 宽度为8,精度为2
@Column(precision = 8, scale = 2)
private Double salary;
// 默认值为1
@Column(columnDefinition = "boolean default 1")
private boolean sex;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
B.getCurrentSession
1.openSession()和getCurrentSession()区别
openSession()每次都会新建一个Session
getCurrentSession首先从上下文中查找是否有session,有则获取,无则新建
getCurrentSession需要有对应的事物支持,当事务结束时会自动关闭session
openSession必须手动关闭
getCurrentSession的使用需要有额外配置
<property name="hibernate.current_session_context_class">thread</property>
2.引入getCurrentSession()后的工具类
package org.wpf.util;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
public class HibernateSessionFactory {
private static SessionFactory sessionFactory;
static {
buildSessionFactory();
}
// 私有构造
private HibernateSessionFactory() {
}
// 获取SessionFactory
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
// 创建session工厂
private static void buildSessionFactory() throws HibernateException {
// 如果没有
if (sessionFactory == null) {
ServiceRegistry sr = new StandardServiceRegistryBuilder().configure().build();
sessionFactory = new MetadataSources(sr).buildMetadata().buildSessionFactory();
}
}
}
3.过滤器
package org.wpf.fliter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.wpf.util.HibernateSessionFactory;
public class OpenSessionInViewFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
try {
// 开启事物
HibernateSessionFactory.getSessionFactory().getCurrentSession().beginTransaction();
// 放行
arg2.doFilter(arg0, arg1);
// 提交事物
HibernateSessionFactory.getSessionFactory().getCurrentSession().getTransaction().commit();
} catch (Exception e) {
// 回滚
HibernateSessionFactory.getSessionFactory().getCurrentSession().getTransaction().rollback();
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
C.映射关系
1.常见映射关系
一对一
一对多或多对一
多对多
关联关系实际开发中可以分为单向关联和双相关联
2.一对多查询
一对多或多对一的关联在实际开发中用的比较多
一个简单的例子就是客户与订单的关系
一个客户可能发出多个订单,而每个订单只属于一个客户
这样,如果从客户指向订单,这种关系就属于一对多的关系
在关系数据库中,只有存在外键参照关系,而且总是由many方参照one方
因此,在关系数据库中,实际支持多对一或一对一的单项关联即可
3.Oracle中的SQL可以分为4大类
DDL数据定义语言 create drop alter truncate
DML数据操纵语言 insert update delete select
DCL数据控制语言 grant revoke [with admin option 和 with grant option]
TCL事物控制语言 commit rollback savepoint
4.截断操作 truncate table t_users
truncate属于DDL,没有事物的概念,删除后没有办法恢复
不会记录日志信息,所以删除大量数据时,执行效率远高于delete from
5.定义一对多
一方Customer
package org.wpf.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Customer implements Serializable {
private static final long serialVersionUID = 4313768320545350900L;
private Long id;
private String name;
// 这是类中表示1对多关联的方式,表示一个Customer中包含了多个Order
private Set<Order> orders = new HashSet<>(0);
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", orders=" + orders + "]";
}
}
Customer.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.wpf.entity.Customer" table="t_customer">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="20" not-null="true" />
</property>
<set name="orders" inverse="true" cascade="all">
<key>
<column name="customer_id" not-null="true" />
</key>
<one-to-many class="org.wpf.entity.Order" />
</set>
</class>
</hibernate-mapping>
多方Order
package org.wpf.entity;
import java.io.Serializable;
import java.util.Date;
public class Order implements Serializable {
private static final long serialVersionUID = 5875230206918806994L;
private Long id;
private Customer customer;
private Date oDate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Date getoDate() {
return oDate;
}
public void setoDate(Date oDate) {
this.oDate = oDate;
}
@Override
public String toString() {
return "Order [id=" + id + ", customer=" + customer + ", oDate=" + oDate + "]";
}
}
Order.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.wpf.entity.Order" table="T_ORDER">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="identity" />
</id>
<many-to-one name="customer" class="org.wpf.entity.Customer"
fetch="select">
<column name="customer_id" not-null="true" />
</many-to-one>
<property name="oDate" type="java.util.Date">
<column name="odate" length="19" not-null="true" />
</property>
</class>
</hibernate-mapping>
在配置文件中添加映射
<mapping resource="org/wpf/entity/Customer.hbm.xml"/>
<mapping resource="org/wpf/entity/Order.hbm.xml"/>测试类
package org.wpf.entity;
import java.util.Date;
import org.hibernate.Session;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.wpf.util.HibernateSessionFactory;
class Test01 {
@BeforeEach
void setUp() throws Exception {
HibernateSessionFactory.getSessionFactory().getCurrentSession().beginTransaction();
}
@AfterEach
void tearDown() throws Exception {
HibernateSessionFactory.getSessionFactory().getCurrentSession().getTransaction().commit();
}
@Test
void test() {
// 级联需要互相通知
Customer c1 = new Customer();
c1.setName("Tom");
Order o1 = new Order();
o1.setoDate(new Date());
Order o2 = new Order();
o2.setoDate(new Date());
// 相互通知
c1.getOrders().add(o1);
o1.setCustomer(c1);
c1.getOrders().add(o2);
o2.setCustomer(c1);
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
session.save(c1);
}
}
控制台信息
Hibernate:
create table t_customer (
ID bigint not null auto_increment,
NAME varchar(20) not null,
primary key (ID)
) engine=InnoDB
Hibernate:
create table T_ORDER (
ID bigint not null auto_increment,
customer_id bigint not null,
odate datetime not null,
primary key (ID)
) engine=InnoDB
Hibernate:
alter table T_ORDER
add constraint FKfiait2tmbi08bkn450b9c5i54
foreign key (customer_id)
references t_customer (ID)
Hibernate:
insert
into
t_customer
(NAME)
values
(?)
Hibernate:
insert
into
T_ORDER
(customer_id, odate)
values
(?, ?)
Hibernate:
insert
into
T_ORDER
(customer_id, odate)
values
(?, ?)运行结果
6.inverse和cascade
inverse的真正作用就是指定由哪一方来维护之间的关联关系
当一方中制订了inverse=false默认,那么那一方就有责任负责之间的关联关系
就是hibernate如何生成sql来维护关联的记录
区别:
Inverse负责控制关系,默认为false,也就是两端都能控制
但造成一些问题,更新时会因为两端都控制,于是重复更新
一般有一端要设为true
cascade负责控制关联对象的级联操作,包括更新,删除等
也就是说对一个对象进行更新,删除时,其他对象也受影响
那么跟他是多对一的关系的对象也全部被删除
7.其他属性
<set>元素包括以下属性
name:设定待映射的持久化类的属性名
cascade:当取值为save_update时,表示级联保存和更新
<set>元素还可以包括<key>和<one-to-many>两个子元素
<key>元素设定与所关联的持久化类对应表的外键
<one-to-many>元素设定所关联的持久化类
<many-to-one>元素建立了订单和客户表的外键之间的映射
name:设置待映射的持久化类的属性名
column:设定和持久化类的属性对应的表的外键
class:设定持久化类的属性类型
not-null:如果为true,表示客户属性不允许为空
fetech="select":抓取策略的设置,表示获取订单后如何获取对应的客户信息
将fetch修改为join,表示获取客户信息时不是采用发送额外的select语句进行获取,而是采用inner join的方式直接查询客户信息,不会产生额外的SQL语句,采用这样的方式查询效率会略高于发送额外查询的方式
8.注解定义的方式
customer
package org.wpf.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
@Entity(name = "t_customer")
public class Customer implements Serializable {
private static final long serialVersionUID = 4313768320545350900L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 32, nullable = false)
private String name;
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
@OrderBy("id desc")
private Set<Order> orders = new HashSet<>(0);
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", orders=" + orders + "]";
}
}
order
package org.wpf.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity(name = "t_order")
public class Order implements Serializable {
private static final long serialVersionUID = 5875230206918806994L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "all_price", precision = 8, scale = 2)
private Double allPrice;
@ManyToOne(optional = false)
@JoinColumn(name = "customer_id")
private Customer customer;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Double getAllPrice() {
return allPrice;
}
public void setAllPrice(Double allPrice) {
this.allPrice = allPrice;
}
@Override
public String toString() {
return "Order [id=" + id + ", allPrice=" + allPrice + ", customer=" + customer + "]";
}
}
设置配置文件
<mapping class="org.wpf.entity.Customer"/>
<mapping class="org.wpf.entity.Order"/>运行结果
Hibernate:
create table t_customer (
id bigint not null auto_increment,
name varchar(32) not null,
primary key (id)
) engine=InnoDB
Hibernate:
create table t_order (
id bigint not null auto_increment,
all_price double precision,
customer_id bigint not null,
primary key (id)
) engine=InnoDB
Hibernate:
alter table t_order
add constraint FKesy3n2gc3fa0s3trrk3tvyv9a
foreign key (customer_id)
references t_customer (id)
Hibernate:
insert
into
t_customer
(name)
values
(?)
Hibernate:
insert
into
t_order
(all_price, customer_id)
values
(?, ?)
Hibernate:
insert
into
t_order
(all_price, customer_id)
values
(?, ?)
9.一对一
实现方式:
共享主键和唯一外键
10.共享主键
既是主键,又是外键,主控方和受控方
a.xml
Person主控方
package org.wpf.entity;
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = -6446631496216328660L;
private Long id;
private String name;
private Card card;
public Person() {
super();
}
public Person(Long id, String name, Card card) {
super();
this.id = id;
this.name = name;
this.card = card;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
}
Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 22:27:49 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Person" table="t_person">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="10" not-null="true" />
</property>
<one-to-one name="card" class="org.wpf.entity.Card"
cascade="all"></one-to-one>
</class>
</hibernate-mapping>
Card受控方
package org.wpf.entity;
import java.io.Serializable;
public class Card implements Serializable {
private static final long serialVersionUID = 7490343597638703173L;
private Long id;
private Person person;
private String city;
public Card() {
super();
}
public Card(Long id, Person person, String city) {
super();
this.id = id;
this.person = person;
this.city = city;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
Card.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 22:27:49 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Card" table="t_card" catalog="test">
<id name="id" type="java.lang.Long">
<column name="ID" />
<!-- 表明根据对方的主键来生成自己的主键,自己并不能独立生成主键 ,这里表示身份证的主键值是从它属性person的id值中获取的 -->
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<!-- constrained="true"表示当前类是受控方,受Person的控制 -->
<one-to-one name="person" class="org.wpf.entity.Person"
constrained="true" />
<property name="city" type="java.lang.String">
<column name="CITY" length="32" />
</property>
</class>
</hibernate-mapping>
b.注解
Husband主控方
package org.wpf.entity;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
@Entity(name = "t_husband") // 主控方
public class Husband implements Serializable {
private static final long serialVersionUID = 7204300104344481060L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 20, nullable = false)
private String name;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "husband")
private Wife wife;
public Husband() {
super();
}
public Husband(Long id, String name, Wife wife) {
super();
this.id = id;
this.name = name;
this.wife = wife;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Wife getWife() {
return wife;
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
Wife受控方
package org.wpf.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
@Entity(name = "t_wife")
public class Wife implements Serializable {
private static final long serialVersionUID = -6685649713801290134L;
@Id
@GenericGenerator(name = "ff1", strategy = "foreign", parameters = {
@Parameter(name = "property", value = "husband") })
@GeneratedValue(generator = "ff1")
private Long id;
@Column(length = 32)
private String name;
@OneToOne(orphanRemoval = true)
@PrimaryKeyJoinColumn
private Husband husband;
public Wife() {
super();
}
public Wife(Long id, String name, Husband husband) {
super();
this.id = id;
this.name = name;
this.husband = husband;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Husband getHusband() {
return husband;
}
public void setHusband(Husband husband) {
this.husband = husband;
}
}
@GenericGenerator(name = "foreignKey"
生成器名称,供GeneratedValue中进行调用
strategy = "foreign" 使用hibernate的外键策略
parameters = @Parameter(value = "article参数值",name = "property参数名称"))//指定成员属性中的article所在类的主键为本类的主键,这里的参数属性name必须为"property"
@GeneratedValue(generator = "foreignKey")//使用上述定义的id生成器
11.唯一外键的关联实现方式
a.xml(bean和上面的一样,省略)
Husband.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 22:47:11 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Husband" table="HUSBAND">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="20" not-null="true" />
</property>
<one-to-one name="wife" class="org.wpf.entity.Wife"
cascade="all" property-ref="husband" />
</class>
</hibernate-mapping>
Wife.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 22:47:11 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Wife" table="WIFE">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" length="20" not-null="true" />
</property>
<many-to-one name="husband" class="org.wpf.entity.Husband"
unique="true" column="husband_id" />
</class>
</hibernate-mapping>
b.注解
Person
package org.wpf.entity;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
@Entity(name = "t1_person")
public class Person implements Serializable {
private static final long serialVersionUID = -6446631496216328660L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 32)
private String name;
@OneToOne(mappedBy = "person", cascade = CascadeType.ALL)
private Card card;
public Person() {
super();
}
public Person(Long id, String name, Card card) {
super();
this.id = id;
this.name = name;
this.card = card;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
}
Card
package org.wpf.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
@Entity(name = "t1_person")
public class Card implements Serializable {
private static final long serialVersionUID = -5345063387498725762L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 32)
private String name;
@OneToOne(optional = false)
@JoinColumn(name = "person_id")
private Person person;
public Card() {
super();
}
public Card(Long id, String name, Person person) {
super();
this.id = id;
this.name = name;
this.person = person;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
12.多对多关联
在关系型数据库中是不能直接表达多对多关联,必须引入一个中间表
注意中间表表中不能包含非键列。中间表没有对应的映射文件
Student
package org.wpf.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Student implements Serializable {
private static final long serialVersionUID = 7767264496828265124L;
private Long id;
private String name;
private Set courses = new HashSet(0);
public Student() {
super();
}
public Student(Long id, String name, Set courses) {
super();
this.id = id;
this.name = name;
this.courses = courses;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getCourses() {
return courses;
}
public void setCourses(Set courses) {
this.courses = courses;
}
}
Student.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.wpf.entity.Student" table="t_student">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="Name" length="20" not-null="true" />
</property>
<set name="courses" table="t_choice" cascade="all">
<key>
<column name="Student_id" not-null="true" />
</key>
<many-to-many entity-name="org.wpf.entity.Course">
<column name="Course_id" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
Course
package org.wpf.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Course implements Serializable {
private static final long serialVersionUID = -2850799906496654565L;
private Long id;
private String title;
private Set students = new HashSet(0);
public Course() {
super();
}
public Course(Long id, String title, Set students) {
super();
this.id = id;
this.title = title;
this.students = students;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Set getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
}
Course.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-1-22 23:00:29 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="org.wpf.entity.Course" table="t_course">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="title" type="java.lang.String">
<column name="TITLE" length="50" not-null="true" />
</property>
<set name="students" inverse="true" table="t_choice">
<key>
<column name="Course_id" not-null="true" />
</key>
<many-to-many entity-name="org.wpf.entity.Student">
<column name="Student_id" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
控制台信息
Hibernate:
create table t_choice (
Course_id bigint not null,
Student_id bigint not null,
primary key (Student_id, Course_id)
) engine=InnoDB
Hibernate:
create table t_course (
ID bigint not null auto_increment,
TITLE varchar(50) not null,
primary key (ID)
) engine=InnoDB
Hibernate:
create table t_student (
ID bigint not null auto_increment,
Name varchar(20) not null,
primary key (ID)
) engine=InnoDB
Hibernate:
alter table t_choice
add constraint FK93ey2xm8fobois7ev90lrrefd
foreign key (Student_id)
references t_student (ID)
Hibernate:
alter table t_choice
add constraint FKjd0jtvxffqm4e7yi50ed1frju
foreign key (Course_id)
references t_course (ID)查看数据库
13.Hibernate注解规范的文档中提供了三种方法
将组件类注解为@Embeddable,并将组件的属性注解为@Id
public class UserRole implements Serializable { @EmbeddedId private UserRolePK pk; }
将组件的属性注解为@ EmbeddedId
@Embeddable
public class UserId implements Serializable {
@Id
UserId uid;
}将类注解为@IdClass,并将该实体中所有主键属性注解为@Id,最常用的方法
需要根据所有的主键属性,建立一个主键类
主键类必须实现序列化接口(Serializable)
主键类必须有默认的public无参数的构造方法
主键类必须覆盖equals和hashCode方法
@IdClass(IPMapKey.class)
public class IPMap {
@Id @Column(name="IP")
private String ip;
@Id @Column(name="ExamPlaceId")
private String examPlaceId;
}
相关文章推荐
- hibernate3.3.2学习笔记---getCurrentSession()与openSession()
- Hibernate学习笔记(四)----核心开发接口、对象的三种状态、session常用方法
- Hibernate框架学习(第三讲)---openSession 和getCurrentSession的区别
- 【JavaEE学习笔记】Hibernate_01_配置,核心,Session,事物,Jboss Tools
- Hibernate学习04---Hibernate对象三种状态以及openSessoin/getCurrentSession
- [原创]java WEB学习笔记79:Hibernate学习之路--- 四种对象的状态,session核心方法:save()方法,persist()方法,get() 和 load() 方法,update()方法,saveOrUpdate() 方法,merge() 方法,delete() 方法,evict(),hibernate 调用存储过程,hibernate 与 触发器协同工作
- 自己学习Hibernate时的一个低级错误:sessionFactory.getCurrentSession()空指针异常
- Hibernate的一个开发工具(OpenSession()和getCurrentSession())
- Hibernate学习笔记之Session-API实现CRUD以及get&load&merge方法
- Hibernate学习笔记---通过load和get方法来查询对象(只能根据主键来查询)
- Hibernate学习笔记:session操作对象
- hibernate 使用sessionfactory的getCurrentSession()方法发生异常
- hibernate的openSessionFactory和getCurrentSession
- Hibernate getCurrentSession 与 openSession() 的区别
- Hibernate openSession() 和 getCurrentSession的区别
- hibernate 的SessionFactory的getCurrentSession 与 openSession() 的区别
- 框架学习之Hibernate 第三节 session接口以及get/load/persist方法
- Hibernate学习笔记:session操作对象
- 用Hibernate开发遇到"No CurrentSessionContext configured"错误
- Hibernate中的getCurrentSession和openSession