Hibernate4

Hibernate3 太长,此文紧接Hibernate3

多对多

建表原则:创建中间表,中间表中至少两个字段作为外键,分别指向多对多双方的主键
在Java中采用对象关系来描述:在A中定义B类类型的Set集合,在B类中定义A类类型的Set集合,使用Set集合是为了避免数据的重复。

SQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
CREATE TABLE `sys_role` (
`role_id` bigint(32) NOT NULL AUTO_INCREMENT,
`role_name` varchar(32) NOT NULL COMMENT '角色名称',
`role_memo` varchar(128) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;


CREATE TABLE `sys_user` (
`user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`user_code` varchar(32) NOT NULL COMMENT '用户账号',
`user_name` varchar(64) NOT NULL COMMENT '用户名称',
`user_password` varchar(32) NOT NULL COMMENT '用户密码',
`user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;


CREATE TABLE `sys_user_role` (
`role_id` bigint(32) NOT NULL COMMENT '角色id',
`user_id` bigint(32) NOT NULL COMMENT '用户id',
PRIMARY KEY (`role_id`,`user_id`),
KEY `FK_user_role_user_id` (`user_id`),
CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建实体

用户实体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package me.yanrs.domain;

import java.util.HashSet;
import java.util.Set;

import me.yanrs.domain.Role;

public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private Byte user_state;

private Set<Role> roles = new HashSet<Role>();

public Long getUser_id() {
return user_id;
}

public void setUser_id(Long user_id) {
this.user_id = user_id;
}

public String getUser_code() {
return user_code;
}

public void setUser_code(String user_code) {
this.user_code = user_code;
}

public String getUser_name() {
return user_name;
}

public void setUser_name(String user_name) {
this.user_name = user_name;
}

public String getUser_password() {
return user_password;
}

public void setUser_password(String user_password) {
this.user_password = user_password;
}

public Byte getUser_state() {
return user_state;
}

public void setUser_state(Byte user_state) {
this.user_state = user_state;
}

public Set<Role> getRoles() {
return roles;
}

public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
角色实体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package me.yanrs.domain;

import java.util.HashSet;
import java.util.Set;

public class Role {
private Long role_id;
private String role_name;
private String role_memo;

private Set<User> users = new HashSet<User>();

public Long getRole_id() {
return role_id;
}

public void setRole_id(Long role_id) {
this.role_id = role_id;
}

public String getRole_name() {
return role_name;
}

public void setRole_name(String role_name) {
this.role_name = role_name;
}

public String getRole_memo() {
return role_memo;
}

public void setRole_memo(String role_memo) {
this.role_memo = role_memo;
}

public Set<User> getUsers() {
return users;
}

public void setUsers(Set<User> users) {
this.users = users;
}
}

配置关系映射

User.hbm.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?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 package="me.yanrs.domain">
<class name="User" table="sys_user">
<id name="user_id">
<generator class="native"></generator>
</id>
<property name="user_code" column="user_code"></property>
<property name="user_name" column="user_name"></property>
<property name="user_password" column="user_password"></property>
<property name="user_state" column="user_state"></property>
<!--
set:
name: 关联的另一方的集合的属性名称
table: 中间表的名称
key:
column: 当前对象在中间表中的外键的名称
many-to-many:
class: 关联另一方的类的全路径
column: 关联另一方在中间表中的外键名称
-->
<set name="roles" table="sys_user_role">
<key column="user_id"></key>
<many-to-many class="me.yanrs.domain.Role" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
Role.hbm.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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 package="me.yanrs.domain">
<class name="Role" table="sys_role">
<id name="role_id">
<generator class="native"></generator>
</id>
<property name="role_name" column="role_name"></property>
<property name="role_memo" column="role_memo"></property>
<!--
set:
name: 关联的另一方的集合的属性名称
table: 中间表的名称
key:
column: 当前对象在中间表中的外键的名称
many-to-many:
class: 关联另一方的类的全路径
column: 关联另一方在中间表中的外键名称
-->
<set name="users" table="sys_user_role">
<key column="role_id"></key>
<many-to-many class="me.yanrs.domain.User" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
hibernate.cfg.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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.url">jdbc:mysql:///test1</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>

<!-- create可以自动根据实体创建数据库,update不创建 -->
<property name="hibernate.hbm2ddl.auto">update</property>

<property name="hibernate.current_session_context_class">thread</property>

<!-- 将实体对象的hibernate的xml文件放到此处,不然会提示 Unknown entity-->
<mapping resource="me/yanrs/domain/Customer.hbm.xml" />
<mapping resource="me/yanrs/domain/Linkman.hbm.xml" />
<mapping resource="me/yanrs/domain/Role.hbm.xml" />
<mapping resource="me/yanrs/domain/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
新增
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package me.yanrs.service;

import java.awt.print.Printable;

import org.hibernate.Session;
import org.hibernate.Transaction;

import me.yanrs.domain.Customer;
import me.yanrs.domain.Linkman;
import me.yanrs.domain.Role;
import me.yanrs.domain.User;
import me.yanrs.utils.HibernateUtils;

public class one_to_many {
public static void main(String[] args) {
// one2many_base();
// one2many_no_cascade();
// one2many_delete_customer_no_cascade();
many2many_no_cascade();
}

private static void many2many_no_cascade() {
Session session = HibernateUtils.getCurrentSession();
//开启事务
Transaction beginTransaction = session.beginTransaction();

User user = new User();
user.setUser_name("user11");

User user2 = new User();
user2.setUser_name("user22");

//创建两个角色
Role role = new Role();
role.setRole_name("role11");

Role role2 = new Role();
role2.setRole_name("role22");

role.getUsers().add(user);
role.getUsers().add(user2);
role2.getUsers().add(user2);
role2.getUsers().add(user);

session.save(user);
session.save(user2);
session.save(role);
session.save(role2);

//不要忘记提交
beginTransaction.commit();
}
}

inverse

在多对多的保存操作中,如果进行了双向维护关系,就必须有一方放弃外键的维护权。一般由被动方放弃。用户主动选择角色,角色是被选择的,所以一般角色要放弃外键的维护权。但如果只进行单向维护关系,那么就不需要放弃外键维护权。

级联操作

在多对多中级联操作同样也有方向性的,例如 用户 和 角色 。如果要以用户为主控方,那么就需要在用户的配置文件中进行cascade配置,反之如果要以联系人为主控方,那么就需要在联系人的配置文件中进行cascade配置。

  1. 保存用户级联角色
    Role.hbm.xml配置 (放弃维护外键)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <?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 package="me.yanrs.domain">
    <class name="Role" table="sys_role">
    <id name="role_id">
    <generator class="native"></generator>
    </id>
    <property name="role_name" column="role_name"></property>
    <property name="role_memo" column="role_memo"></property>
    <!--
    set:
    name: 关联的另一方的集合的属性名称
    table: 中间表的名称
    key:
    column: 当前对象在中间表中的外键的名称
    many-to-many:
    class: 关联另一方的类的全路径
    column: 关联另一方在中间表中的外键名称
    -->
    <set inverse="true" name="users" table="sys_user_role">
    <key column="role_id"></key>
    <many-to-many class="me.yanrs.domain.User" column="user_id"></many-to-many>
    </set>
    </class>
    </hibernate-mapping>

User.hbm.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?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 package="me.yanrs.domain">
<class name="User" table="sys_user">
<id name="user_id">
<generator class="native"></generator>
</id>
<property name="user_code" column="user_code"></property>
<property name="user_name" column="user_name"></property>
<property name="user_password" column="user_password"></property>
<property name="user_state" column="user_state"></property>
<!--
set:
name: 关联的另一方的集合的属性名称
table: 中间表的名称
key:
column: 当前对象在中间表中的外键的名称
many-to-many:
class: 关联另一方的类的全路径
column: 关联另一方在中间表中的外键名称
-->
<set cascade="save-update" name="roles" table="sys_user_role">
<key column="user_id"></key>
<many-to-many class="me.yanrs.domain.Role" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package me.yanrs.service;

import org.hibernate.Session;
import org.hibernate.Transaction;

import me.yanrs.domain.Customer;
import me.yanrs.domain.Linkman;
import me.yanrs.domain.Role;
import me.yanrs.domain.User;
import me.yanrs.utils.HibernateUtils;

public class one_to_many {
public static void main(String[] args) {
// one2many_base();
// one2many_no_cascade();
// one2many_delete_customer_no_cascade();
//many2many_no_cascade();
many2many_cascade();
}

private static void many2many_cascade() {
Session session = HibernateUtils.getCurrentSession();
//开启事务
Transaction beginTransaction = session.beginTransaction();

User user = new User();
user.setUser_name("user11");

User user2 = new User();
user2.setUser_name("user22");

//创建两个角色
Role role = new Role();
role.setRole_name("role11");

Role role2 = new Role();
role2.setRole_name("role22");

user.getRoles().add(role);
user2.getRoles().add(role2);

session.save(user);
session.save(user2);

//不要忘记提交
beginTransaction.commit();

}
}

  1. 保存角色级联用户
    Role.hbm.xml配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <?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 package="me.yanrs.domain">
    <class name="Role" table="sys_role">
    <id name="role_id">
    <generator class="native"></generator>
    </id>
    <property name="role_name" column="role_name"></property>
    <property name="role_memo" column="role_memo"></property>
    <!--
    set:
    name: 关联的另一方的集合的属性名称
    table: 中间表的名称
    key:
    column: 当前对象在中间表中的外键的名称
    many-to-many:
    class: 关联另一方的类的全路径
    column: 关联另一方在中间表中的外键名称
    -->
    <set cascade="save-update" name="users" table="sys_user_role">
    <key column="role_id"></key>
    <many-to-many class="me.yanrs.domain.User" column="user_id"></many-to-many>
    </set>
    </class>
    </hibernate-mapping>

User.hbm.xml配置(放弃外键的维护)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?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 package="me.yanrs.domain">
<class name="User" table="sys_user">
<id name="user_id">
<generator class="native"></generator>
</id>
<property name="user_code" column="user_code"></property>
<property name="user_name" column="user_name"></property>
<property name="user_password" column="user_password"></property>
<property name="user_state" column="user_state"></property>
<!--
set:
name: 关联的另一方的集合的属性名称
table: 中间表的名称
key:
column: 当前对象在中间表中的外键的名称
many-to-many:
class: 关联另一方的类的全路径
column: 关联另一方在中间表中的外键名称
-->
<set inverse="true" name="roles" table="sys_user_role">
<key column="user_id"></key>
<many-to-many class="me.yanrs.domain.Role" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package me.yanrs.service;

import org.hibernate.Session;
import org.hibernate.Transaction;

import me.yanrs.domain.Customer;
import me.yanrs.domain.Linkman;
import me.yanrs.domain.Role;
import me.yanrs.domain.User;
import me.yanrs.utils.HibernateUtils;

public class one_to_many {
public static void main(String[] args) {
// one2many_base();
// one2many_no_cascade();
// one2many_delete_customer_no_cascade();
//many2many_no_cascade();
many2many_cascade();
}

private static void many2many_cascade() {
Session session = HibernateUtils.getCurrentSession();
//开启事务
Transaction beginTransaction = session.beginTransaction();

User user = new User();
user.setUser_name("user11");

User user2 = new User();
user2.setUser_name("user22");

//创建两个角色
Role role = new Role();
role.setRole_name("role11");

Role role2 = new Role();
role2.setRole_name("role22");

role.getUsers().add(user);
role.getUsers().add(user2);
role2.getUsers().add(user);
role2.getUsers().add(user2);

session.save(role);
session.save(role2);

//不要忘记提交
beginTransaction.commit();

}
}

  1. 新增
    为Role新增一个用户(上面代码中的配置不变【上面的配置是User放弃外键的维护,cascade=”save-update” 】)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    package me.yanrs.service;

    import org.hibernate.Session;
    import org.hibernate.Transaction;

    import com.sun.jndi.toolkit.url.Uri;

    import me.yanrs.domain.Customer;
    import me.yanrs.domain.Linkman;
    import me.yanrs.domain.Role;
    import me.yanrs.domain.User;
    import me.yanrs.utils.HibernateUtils;

    public class one_to_many {
    public static void main(String[] args) {
    // one2many_base();
    // one2many_no_cascade();
    // one2many_delete_customer_no_cascade();
    //many2many_no_cascade();
    // many2many_cascade();
    add_user_for_role();
    }

    private static void add_user_for_role() {
    Session session = HibernateUtils.getCurrentSession();
    //开启事务
    Transaction beginTransaction = session.beginTransaction();
    User user = new User();
    user.setUser_name("new_user");

    Role role = session.get(Role.class, 1l);
    role.getUsers().add(user);

    //持久化对象无需save,直接commit即可
    beginTransaction.commit();

    }

  2. 删除
    删除User的时候,删除对应的角色。配置为User.hbm.xml中cascade=”delete”,Role.hbm.xml中inverse=”true”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package me.yanrs.service;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.sun.jndi.toolkit.url.Uri;

import me.yanrs.domain.Customer;
import me.yanrs.domain.Linkman;
import me.yanrs.domain.Role;
import me.yanrs.domain.User;
import me.yanrs.utils.HibernateUtils;

public class one_to_many {
public static void main(String[] args) {
// one2many_base();
// one2many_no_cascade();
// one2many_delete_customer_no_cascade();
//many2many_no_cascade();
// many2many_cascade();
//add_user_for_role();
delete_user();
}

private static void delete_user() {
Session session = HibernateUtils.getCurrentSession();
//开启事务
Transaction beginTransaction = session.beginTransaction();
User user = session.get(User.class, 1l);

Role role = session.get(Role.class, 1l);
Role role2 = session.get(Role.class, 2l);

user.getRoles().remove(role);
user.getRoles().remove(role2);

//持久化对象无需save,直接commit即可

beginTransaction.commit();

}

多对多的关系主要是靠中间表来维护的,在Hibernate中多对多主要是靠关联的集合来维护的,所以我们只需关心如何操作集合即可。

总结

级联操作的取值可以是save-update、delete、all
inverse的默认值是false,代表维护外键,ture为不维护外键

  1. 一对多中
    主控方进行级联操作的配置,一的一方应该放弃外键的维护

  2. 多对多中
    必须有一方要放弃主键的维护,一般是被动方放弃主键的维护,主动方进行级联操作的配置