1、数据库表与表的关系
2、hibernate一对多的配置
-
创建数据库和表
- 自行建数据库
-
建表
CREATE TABLE `cst_customer` ( `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)', `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)', `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话', PRIMARY KEY (`cust_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `cst_linkmain` ( `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)', `lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名', `lkm_cust_id` bigint(32) DEFAULT NULL COMMENT '客户id(外键)', PRIMARY KEY (`lkm_id`), KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`), CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-
分别创建实体类
要点:在多的一方的写实体类的时候不写外键属性,要创建一的一方的对象并生成相应的set/get方法 ;在一的一方创建多的一方的集合并初始化,并生成相应的ser/get方法。hibernate默认的集合石set,也可以使用list。
-
一的一方
package com.chun.domain; import java.util.HashSet; import java.util.Set; /* * 客户的实体类*/ public class Customer { private Long cust_id; private String cust_name; private String cust_phone; private Set<LinkMain> linkMains = new HashSet<>(); public Set<LinkMain> getLinkMains() { return linkMains; } public void setLinkMains(Set<LinkMain> linkMains) { this.linkMains = linkMains; } public Long getCust_id() { return cust_id; } public void setCust_id(Long cust_id) { this.cust_id = cust_id; } public String getCust_name() { return cust_name; } public void setCust_name(String cust_name) { this.cust_name = cust_name; } public String getCust_phone() { return cust_phone; } public void setCust_phone(String cust_phone) { this.cust_phone = cust_phone; } @Override public String toString() { final String s = cust_id + " " + cust_name + " " + cust_phone; return s; } }
package com.chun.domain; /* * 联系人实体类*/ public class LinkMain { private Long lkm_id; private String lkm_name; //通过ORM表示一个联系人只可以属于一个客户 //放置的一的一方的对像 private Customer customer; public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } public Long getLkm_id() { return lkm_id; } public void setLkm_id(Long lkm_id) { this.lkm_id = lkm_id; } public String getLkm_name() { return lkm_name; } public void setLkm_name(String lkm_name) { this.lkm_name = lkm_name; } //private String lkm_cust_id; }
-
分别创建实体类的映射文件
- 多的一方的映射文件
<!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.chun.domain.LinkMain" table="cst_linkmain"> <id name="lkm_id" column="lkm_id"> <generator class="native"></generator> </id> <property name="lkm_name" column="lkm_name"></property> <!-- 配置多对一的属性:放置的是一的一方的对象--> <!-- many to one--> <!-- name: 一的一方的对象的属性名称--> <!-- class:一的一方对象的全路径--> <!-- column:多的一方的表的外键的名称--> <many-to-one name="customer" class="com.chun.domain.Customer" column="lkm_cust_id"> </many-to-one> </class> </hibernate-mapping>
- 一的一方的映射文件
<!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.chun.domain.Customer" table="cst_customer"> <!-- 建立主键与OID映射--> <id name="cust_id" column="cust_id"> <generator class="native"></generator> </id> <property name="cust_phone" column="cust_phone"></property> <property name="cust_name" column="cust_name"></property> <!-- 配置一对多的映射:放置多的一方的集合--> <!-- set标签--> <!-- name:多的一方的集合的名称--> <set name="linkMains"> <!-- key标签--> <!-- column:多的一方的外键 --> <key column="lkm_cust_id"></key> <!-- one-to-many标签--> <!-- class::多的一方的类的全路径--> <one-to-many class="com.chun.domain.LinkMain"></one-to-many> </set> </class> </hibernate-mapping>
-
-
配置hibernate.cfg.xml核心配置文件
<?xml version='1.0' encoding='utf-8'?> <!--在hibernate-core-5.0.7.Final.jar/org.hibernate/hibernate-configuration-3.0.dtd引入约束--> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 在session-factory中配置基本必需的数据库连接--> <!-- 数据库驱动配置--> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 要连接的数据库--> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatedaythree?useUnicode=true&characterEncoding=UTF8</property> <!-- 用户名--> <property name="hibernate.connection.username">root</property> <!-- 用户密码--> <property name="hibernate.connection.password">980828</property> <!-- 配置hibernate的方言--> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <!-- 可选配置--> <!-- Mysql语句打印配置--> <property name="hibernate.show_sql ">true</property> <!-- 格式化Mysql语句--> <property name="hibernate.format_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <!-- &配置C3P0连接池--> <property name="connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property> <!--在连接池中可用的数据库连接的最少数目 --> <property name="c3p0.min_size">5</property> <!--在连接池中所有数据库连接的最大数目 --> <property name="c3p0.max_size">20</property> <!--设定数据库连接的过期时间,以秒为单位, 如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 --> <property name="c3p0.timeout">120</property> <!--每3000秒检查所有连接池中的空闲连接 以秒为单位--> <property name="c3p0.idle_test_period">3000</property> <!-- 引入映射文件--> <mapping resource="com/chun/domain/Customer.hbm.xml"></mapping> <mapping resource="com/chun/domain/LinkMain.hbm.xml"></mapping> </session-factory> </hibernate-configuration>
-
引入工具类
package com.chun.Utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtils { private static final Configuration configuration; private static final SessionFactory sessionFactory; static { configuration = new Configuration().configure(); sessionFactory = configuration.buildSessionFactory(); } public static Session openSession() { return sessionFactory.openSession(); } public static Session getCurrentSession() { return sessionFactory.getCurrentSession();//需要配置,因为默认没有开启 } }
-
编写测试类(只保存一边是不可以的,需要通过级联配置才可以,分别是级联保存或更新、级联删除)
运行结果
3、hibernate的级联操作
-
什么是级联
-
级联具有方向性
- 操作一的一方,是否操作到多的一方
- 操作多的一方,是否操作到一的一方
-
级联保存或更新
- 保存客户级联联系人
- 看操作的主体是谁,就在谁的配置文件中的另一方对象进行配置
- 看操作的主体是谁,就在谁的配置文件中的另一方对象进行配置
- 保存联系人级联客户
- 保存客户级联联系人
-
级联删除,删除一边的时候,另一边的也删除了
4、hibernate多对多的配置
-
创建数据库和表
- 自行建数据库
-
建表
CREATE TABLE `sys_user` ( `user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id', `user_name` varchar(64) NULL COMMENT '用户名称', `user_password` varchar(32) NULL COMMENT '用户密码', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `sys_role` ( `role_id` bigint(32) NOT NULL AUTO_INCREMENT, `role_name` varchar(32) NULL COMMENT '角色名称', `role_memo` varchar(128) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 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;
-
分别创建实体类
import java.util.HashSet; import java.util.Set; public class User { private long userId; private String userName; private String userPassword; private Set<Role> roles = new HashSet<>(); public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } public long getUserId() { return userId; } public void setUserId(long userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPassword() { return userPassword; } public void setUserPassword(String userPassword) { this.userPassword = userPassword; } }
import java.util.HashSet; import java.util.Set; public class Role { private long roleId; private String roleName; private String roleMemo; private Set<User> users = new HashSet<>(); public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } public long getRoleId() { return roleId; } public void setRoleId(long roleId) { this.roleId = roleId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public String getRoleMemo() { return roleMemo; } public void setRoleMemo(String roleMemo) { this.roleMemo = roleMemo; } }
-
分别创建实体类的映射文件 (在多对多的情况下一定要使一方放弃外键,一般是被选择的一方放弃外键)
<?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.chun.domain.Role" table="sys_role" schema="hibernatedaythree"> <id name="roleId" column="role_id"> <generator class="native"></generator> </id> <property name="roleName" column="role_name"/> <property name="roleMemo" column="role_memo"/> <set name="users" table="sys_user_role" inverse="true"> <key column="role_id"></key> <many-to-many class="com.chun.domain.User" column="user_id"></many-to-many> </set> </class> </hibernate-mapping>
<?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.chun.domain.User" table="sys_user" schema="hibernatedaythree"> <id name="userId" column="user_id"> <generator class="native"></generator> </id> <property name="userName" column="user_name"/> <property name="userPassword" column="user_password"/> <!-- name:多方的集合属性--> <!-- table:中间表--> <set name="roles" table="sys_user_role"> <!-- column:当前的对象对应中间表的外键--> <key column="user_id"></key> <!-- many-to-many--> <!-- class:对方的类的全路径--> <!-- column:对方的主键在中间表的外键--> <many-to-many class="com.chun.domain.Role" column="role_id"></many-to-many> </set> </class> </hibernate-mapping>
一定要注意插入数据库时的编码格式
-
配置hibernate.cfg.xml核心配置文件
<?xml version='1.0' encoding='utf-8'?> <!--在hibernate-core-5.0.7.Final.jar/org.hibernate/hibernate-configuration-3.0.dtd引入约束--> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 在session-factory中配置基本必需的数据库连接--> <!-- 数据库驱动配置--> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 要连接的数据库--> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatedaythree?useUnicode=true&characterEncoding=UTF8</property> <!-- 用户名--> <property name="hibernate.connection.username">root</property> <!-- 用户密码--> <property name="hibernate.connection.password">980828</property> <!-- 配置hibernate的方言--> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <!-- 可选配置--> <!-- Mysql语句打印配置--> <property name="hibernate.show_sql ">true</property> <!-- 格式化Mysql语句--> <property name="hibernate.format_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <!-- &配置C3P0连接池--> <property name="connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property> <!--在连接池中可用的数据库连接的最少数目 --> <property name="c3p0.min_size">5</property> <!--在连接池中所有数据库连接的最大数目 --> <property name="c3p0.max_size">20</property> <!--设定数据库连接的过期时间,以秒为单位, 如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 --> <property name="c3p0.timeout">120</property> <!--每3000秒检查所有连接池中的空闲连接 以秒为单位--> <property name="c3p0.idle_test_period">3000</property> <!-- 设置事务隔离级别--> <property name="hibernate.connection.isolation">4</property> <!-- 配置Session绑定当前对象--> <property name="hibernate.current_session_context_class">thread</property> <!-- 引入映射文件--> <mapping resource="com/chun/domain/Customer.hbm.xml"></mapping> <mapping resource="com/chun/domain/LinkMain.hbm.xml"></mapping> <mapping resource="com/chun/domain/Role.hbm.xml"/> <mapping resource="com/chun/domain/User.hbm.xml"/> </session-factory> </hibernate-configuration>
-
编写测试类(只保存一边是不可以的,需要通过级联配置才可以,分别是级联保存或更新、级联删除)
级联保存或更新–保存客户级联保存角色(被保存的是角色),谁操作在谁的配置文件进行配置,并且外键由谁操作谁维护
级联删除–删除客户级联删除角色(顺带着被删除的是角色),谁操作在谁的配置文件进行配置,并且外键由谁操作谁维护