hibernate5(9)注解映射[1]多对一单向关联
来源:互联网 发布:淘宝c店代运营 编辑:程序博客网 时间:2024/06/05 17:10
在博客网站中,我们可能需要从某一篇文章找到其所关联的作者,这就需要从文章方建立起对用户的关联,即是多对一的映射关系。
现在先看一个配置实例:我们的文章实体类
package com.zeng.model;import javax.persistence.CascadeType;import javax.persistence.Entity;import javax.persistence.FetchType;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Lob;import javax.persistence.ManyToOne;import javax.persistence.OneToMany;import javax.persistence.Table;@Table(name = "t_article")@Entitypublic class Article { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; @Lob//数据可能会非常长,映射为数据库支持的“大对象” private String content; /** * @ManyToOne 使用此标签建立多对一关联,此属性在“多”方使用注解在我们的“一”方属性上 * @cascade 指定级联操作,以数组方式指定,如果只有一个,可以省略“{}” * @fetch 定义抓取策略 * @optional 定义是否为必需属性,如果为必需(false),但在持久化时user = null,则会持久化失败 * @targetEntity 目标关联对象,默认为被注解属性所在类 */ @ManyToOne(cascade ={CascadeType.ALL},fetch = FetchType.LAZY,optional = false,targetEntity = User.class) private User user; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public User getUser() { return user; } public void setUser(User user) { this.user = user; }}
因为这里是单向关联,所以我们无须在在User类中建立对文章的关联属性
接下来编写我们的测试类
package com.zeng.test;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.junit.After;import org.junit.AfterClass;import org.junit.Before;import org.junit.BeforeClass;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.zeng.model.Article;import com.zeng.model.User;public class Test2 { private static ApplicationContext ac; private static SessionFactory sessionFactory; private Session session; private Transaction transaction; @BeforeClass//在测试类初始化时调用此方法,完成静态对象的初始化 public static void before(){ ac = new ClassPathXmlApplicationContext("spring-datasource.xml"); sessionFactory = (SessionFactory) ac.getBean("sessionFactory"); } @Before//每一个被注解Test方法在调用前都会调用此方法一次 public void setup(){//建立针对我们当前测试方法的的会话和事务 session = sessionFactory.openSession(); transaction = session.beginTransaction(); } //测试级联关系映射注解配置:多对一单向关联 @Test public void test1(){ User user = new User(); user.setName("name1"); Article article = new Article(); article.setContent("content1"); article.setUser(user);//建立级联关系 session.save(article);//注意这里我们没有保存我们的user对象 } @After//每一个被注解Test方法在调用后都会调用此方法一次 public void teardown(){ transaction.commit(); session.clear(); session.close(); } @After//在类销毁时调用一次 public void after(){ sessionFactory.close(); }}
调用上面测试方法,我们会发现,hibernate帮我们在上篇文章已建立User类的基础上,又帮我们创建了t_article数据表:
mysql> desc t_article;
+———+————–+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+———+————–+——+—–+———+—————-+
| id | int(11) | NO | PRI | NULL | auto_increment |
| content | varchar(255) | YES | | NULL | |
| user_id | int(11) | NO | MUL | NULL | |
+———+————–+——+—–+———+—————-+
3 rows in set (0.00 sec)然后我们查看用户表和文章表,会看到:
mysql> select * from t_user;
+—-+——-+
| id | name |
+—-+——-+
| 1 | name1 |
+—-+——-+
1 row in set (0.00 sec)mysql> select * from t_article;
+—-+———-+———+
| id | content | user_id |
+—-+———-+———+
| 1 | content1 | 1 |
+—-+———-+———+
1 row in set (0.00 sec)
可以看到,这里我们的user_id和user表的新建记录id是对应的。
看完实例,下面我们针对配置的属性进行具体分析:
1. cascade属性
级联属性对于一方和多方的作用效果是不一样的。经测试发现,在多对一中,多方使用CascadeType.PERSIST无法级联保存对象,必须使用CascadeType.ALL。而级联删除既可使用CascadeType.REMOVE也可使用CascadeType.ALL
对于上述方法,如果我们没有设置级联保存,在我们保存文章对象时,用户对象自然不会持久化到数据库,这时候会报错:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.zeng.model.User
在我们提交事务的时候,hibernate总会flush(清理)我们的session缓存,所谓清理,是指hibernate按照持久化对象的属性变化来同步更新数据库,当发现我们的article对象引用了临时对象user,而article.user.id = null,会判断user对象是瞬时的Transient,这个我们要持久化到数据库中的article对象发生冲突,因此会保存失败。这里我们也意在说明,关系直接的级联映射是通过用户对象标识符id来确认的。意思是说,即使article.user.其它属性全为null,但只要article.user.id在数据库中有相关记录(saved)这时就能建立两者的级联关系了。
另一方面,如果我们习惯了xxx.htm.xml的方式来配置我们的实体映射关系,那我们必然对hibernate的级联属性更加熟悉,这时我们可以通过@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})来使用hibernate内置级联属性。关于hibernate的内置级联属性常见有:
2. @JoinColumn
它的具体值可参照下表
1. 引用关系属性的名称 +“”+ 被引用的主键列的名称。
2. 引用实体的字段名称 +“”+ 被引用的主键列的名称。
3. 如果实体中没有这样的引用关系属性或字段(请参阅 @JoinTable),则连接列名称格式化为以下名称的连接:实体名称 +“_”+ 被引用的主键列的名称。这是外键列的名称。如果连接针对“一对一”或“多对一”实体关系,则该列位于源实体的表中。如果连接针对“多对多”实体关系,则该列位于连接表(请参阅 @JoinTable)中。
4. 如果连接列名难于处理、是一个保留字、与预先存在的数据模型不兼容或作为数据库中的列名无效,请将 name 设置为所需的 String 列名。 nullable true 默认情况下,JPA 持续性提供程序假设允许所有列包含空值。如果不允许该列包含空值,请将nullable 设置为 false。 referencedColumnName 无 如果使用一个连接列,则 JPA 持续性提供程序假设在实体关系中,被引用的列名是被引用的主键列的名称。如果在连接表(请参阅 @JoinTable)中使用,则被引用的键列位于拥有实体(如果连接是反向连接定义的一部分,则为反向实体)的实体表中。要指定其他列名,请将 referencedColumnName 设置为所需的 String 列名。 table 无 JPA 持续性提供程序假设实体的所有持久字段存储到一个名称为实体类名称的数据库表中(请参阅 @Table)。如果该列与辅助表关联(请参阅 @SecondaryTable),请将 name 设置为相应辅助表名称的 String 名称 unique false 默认情况下,JPA 持续性提供程序假设允许所有列包含重复值。如果不允许该列包含重复值,请将 unique 设置为 true。 updatable true 默认情况下,JPA 持续性提供程序假设它可以更新所有表列。如果该列为只读,则将 updatable 设置为 false
参考:http://blog.sina.com.cn/s/blog_4bc179a80100kd0k.html
- hibernate5(9)注解映射[1]多对一单向关联
- 【SSH进阶之路】【九】hibernate5 注解映射【1】 多对一单向关联
- hibernate5(10)注解映射[2]一对多单向关联
- Hibernate多对一单向关联映射
- 多对一单向关联映射
- hibernate:多对一单向关联映射
- Hibernate多对一映射单向关联
- Hibernate多对一关联映射(单向)
- 多对一单向关联映射
- 单向多对一的关联映射
- 【SSH进阶之路】【十】hibernate5 注解映射【2】 一对多单向关联
- hibernate单向多对一关联映射(many-to-one)XML与注解版
- Hibernate关联关系映射-----单向多对一映射配置
- 【SSH系列】Hibernate映射-- 多对一单向关联映射
- Hibernate映射—— 多对一单向关联映射
- hibernate5(14)注解映射[6]多对多中间表关联
- hibernate4- 单向多对一、一对多的关联映射
- Hibernate关系映射(7)_多对一单向关联
- 在涉及到一些参数修改的时候,一定要和医院确认------运维日志32
- DuiLib(8)——Menu菜单的实现方式
- 派生类求两点间的距离、矩形的周长和面积
- hdu 1847 Good Luck in CET-4 Everybody! 博弈
- vector迭代器失效的一种情形
- hibernate5(9)注解映射[1]多对一单向关联
- Android控件 webView
- 方法的继承,覆写和重载
- 软件
- C#WindowsMediaPlayer的属性
- Nginx开机启动设置
- 反素数 51Nod1060 最复杂的数
- 【React Native开发】React Native移植原生Android项目(Mac用)
- system V 消息队列的用法