• 26.Hibernate-主键和映射.md



    目录

    1.复合主键映射

    数据库表可以用复合主键映射。但是复合主键映射使用时候需要注意:在配置文件中,需要使用一个对象来表示复合主键

    • 单一主键
        <class name="Employee" table="employee">
            <!-- 主键 注意和类成员和表列名称的一致对应 -->
            <id name="empId" column="EmpId" >
                <!-- 主键的生成策略:
                     1.identity  自增长(mysql,db2)
                     2.sequence  自增长(序列), oracle中自增长是以序列方法实现
                     3.native  自增长【会根据底层数据库自增长的方式选择identity或sequence】
                                如果是mysql数据库, 采用的自增长方式是identity
                                如果是oracle数据库, 使用sequence序列的方式实现自增长
                        
                     4.increment  自增长(会有并发访问的问题,一般在服务器集群环境使用会存在问题。)
                        
                     5.assigned  指定主键生成策略为手动指定主键的值
                     6.uuid      指定uuid随机生成的唯一的值
                     7.foreign   (外键的方式, one-to-one讲)
                 -->
                <generator class="native" />
                
            </id>
            <!-- 非主键,同样一一映射 
                 name:类的属性名称
                 column:表的字段名称
                 length:设定字段的长度,默认为255
                 type:设定映射表的类型,如果不写匹配类对应属性的类型
                         java类型:必须带完整包名:java.lang.String
                         hibernate类型:全部都是小写
                  
            -->
            <property name="empName" column="EmpName"></property>
            <property name="workDate" column="WorkDate"></property>
        </class>  
    
    
    • 复合主键

    a. 首先需要将数据库表对应的对象类中的复合主键,提取为一个对象。所以需要新建一个类,将这个类对象作为表对象的属性。
    特别要注意的是这个复合主键类对象一定要实现序列化方法

    package per.liyue.code.hibernatehello;
    import java.io.Serializable;
    public class CompositeKeys implements Serializable {
        private String name = null;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        private int id = 0;
    }  
    
    

    b. 将序列化的对象添加到表对应的类对象中

    public class Employee {
        private CompositeKeys  keys;
        private String empName;
        private Date workDate; 
            ......
    
    } 
    
    

    c. 在配置文件中将符合主键配置

        <class name="Employee" table="employee">
            <composite-id name="keys">
                <key-property name="name" type="String"></key-property>
                <key-property name="id" type="int"></key-property>
            </composite-id>
    
    
            <!-- 非主键,同样一一映射 
                 name:类的属性名称
                 column:表的字段名称
                 length:设定字段的长度,默认为255
                 type:设定映射表的类型,如果不写匹配类对应属性的类型
                         java类型:必须带完整包名:java.lang.String
                         hibernate类型:全部都是小写
                  
            -->
            <property name="empName" column="EmpName"></property>
            <property name="workDate" column="WorkDate"></property>
        </class> 
    
    

    目录

    2.集合映射

    2.1Set集合

    假若有如下的数据库表:

    • 那么对应的类对象应该是
    package per.liyue.code.hibernatecollection;
    import java.util.Set;
    /*
     * 带有集合的类
     */
    public class User {
        private int userId;
        private String userName;
        public int getUserId() {
            return userId;
        }
        public void setUserId(int userId) {
            this.userId = userId;
        }
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public Set<String> getUserEmail() {
            return userEmail;
        }
        public void setUserEmail(Set<String> userEmail) {
            this.userEmail = userEmail;
        }
        //一个Set集合,对应数据库中的表,这个表的外键是User表的主键
        private Set<String> userEmail;
    }
    
    • 配置映射文件:
      要注意的是Set集合的配置,对应的数据类型必须填写
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
    <!-- package:类对象所在的包
         auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
         Demo:在true时候可以写为session.createQuery("from Employee").list();
                   在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
     -->
    <hibernate-mapping package="per.liyue.code.hibernatecollection" auto-import="true">
        <!-- 类与表的对应
             name:类名称
             table:表名称
        
         -->
        <class name="User" table="user">
        
            <!-- 主键 注意和类成员和表列名称的一致对应 -->
            <id name="userId" column="UserId" >
                <generator class="native" />            
            </id>
            
            <property name="userName" column="UserName"></property>
            
            <!-- Set集合配置:
                 set-name:要映射的Set集合类
                 set-table:要映射的Set表
                     key-column:指定集合表的外键,也就是User表的主键
                         element-type:集合表其他字段的类型,必须填写!!!
                         element-column:集合表其他自动的表列名称
             -->
            <set name="userEmail" table="UserEmail">
                <key column="UserId"></key>
                <element type="string" column="EmailAddress"></element>
            </set>
            
        </class>
    </hibernate-mapping>  
    
    
    • 配置Hibernate配置文件:
    <!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 name="foo">
            <!-- 数据库连接配置 -->
            <!-- 连接类 -->
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <!-- 连接数据库 -->
            <property name="hibernate.connection.url">jdbc:mysql:///hi</property>
            <!-- 连接用户名 -->
            <property name="hibernate.connection.username">root</property>
            <!-- 连接密码 -->
            <property name="hibernate.connection.password">root</property>
            <!-- 数据库方言 -->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
            
            <!-- 其他配置 -->
            <property name="hibernate.show_sql"></property>
            
            <property name="hibernate.hbm2ddl.auto">update</property>
            
            
            <!-- 加载所有的映射 -->
            <mapping resource="per/liyue/code/hibernatehello/Employee.hbm.xml"/>
            <mapping resource="per/liyue/code/hibernatecollection/User.hbm.xml"/>
        </session-factory>
    </hibernate-configuration>  
    
    
    • 最后保存数据
    package per.liyue.code.hibernatecollection;
    import java.util.HashSet;
    import java.util.Set;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.junit.Test;
    public class App {
        private static SessionFactory sf;
        static{
            sf = new Configuration().configure().buildSessionFactory();
        }
        
        @Test
        public void setOperation(){
            Session s = sf.openSession();
            s.beginTransaction();
            
            /*
             * Set:保存带Set的集合
             */
            User user = new User();
            user.setUserId(2);
            user.setUserName("李四");
            Set<String> email = new HashSet<>();
            email.add("a@a.com");
            email.add("b@b.com");
            user.setUserEmail(email);
            
            s.save(user);
            
            s.getTransaction().commit();
            s.close();
            sf.close();
            
            
        }
    }
    

    2.2其他集合

    其他集合大体上类似Set集合,但是具体有不同

    • list
      list在配置文件中需要指定一个索引,因为list是有序的!!!

    • map
      map中key和value都需要指定类型

    Demo:
    将上文中的例子修改

    package per.liyue.code.hibernatecollection;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    /*
     * 带有集合的类
     */
    public class User {
        private int userId;
        private String userName;
        public int getUserId() {
            return userId;
        }
        public void setUserId(int userId) {
            this.userId = userId;
        }
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public Set<String> getUserEmail() {
            return userEmail;
        }
        public void setUserEmail(Set<String> userEmail) {
            this.userEmail = userEmail;
        }
        //一个Set集合,对应数据库中的表,这个表的外键是User表的主键
        private Set<String> userEmail;
        
        //一个List集合
        private List<String> userPhoneNumber = new ArrayList<>();
        public List<String> getUserPhoneNumber() {
            return userPhoneNumber;
        }
        public void setUserPhoneNumber(List<String> userPhoneNumber) {
            this.userPhoneNumber = userPhoneNumber;
        }
        
        //一个Map集合
        private Map<String, String> userAddress = new HashMap<>();
        public Map<String, String> getUserAddress() {
            return userAddress;
        }
        public void setUserAddress(Map<String, String> userAddress) {
            this.userAddress = userAddress;
        }
        
    }
    
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
    <!-- package:类对象所在的包
         auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
         Demo:在true时候可以写为session.createQuery("from Employee").list();
                   在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
     -->
    <hibernate-mapping package="per.liyue.code.hibernatecollection" auto-import="true">
        <!-- 类与表的对应
             name:类名称
             table:表名称
        
         -->
        <class name="User" table="user">
        
            <!-- 主键 注意和类成员和表列名称的一致对应 -->
            <id name="userId" column="user_id" >
                <generator class="native" />            
            </id>
            
            <property name="userName" column="user_name"></property>
            
            <!-- Set集合配置:
                 set-name:要映射的Set集合类
                 set-table:要映射的Set表
                     key-column:指定集合表的外键,也就是User表的主键
                         element-type:集合表其他字段的类型
                         element-column:集合表其他自动的表列名称
             -->
            <set name="userEmail" table="UserEmail">
                <key column="user_id"></key>
                <element type="string" column="email_address"></element>
            </set>
            
            <!-- List集合配置
                 list-index:需要为list指定排序,因为list是有序的
             -->
            <list name="userPhoneNumber" table="UserPhoneNumber">
                <key column="user_id"></key>
                <list-index column="list_index"></list-index>
                <element type="string" column="phone_number"></element>
            </list>
            
            <!-- Map集合配置
                
             -->
             <map name="userAddress">
                 <key column="user_id"></key>
                 <map-key type="string" column="area"></map-key>
                 <element type="string" column="address"></element>
             </map>
            
        </class>
    </hibernate-mapping>  
    
    

    最后再修改实现类

    package per.liyue.code.hibernatecollection;
    import java.util.HashSet;
    import java.util.Set;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.junit.Test;
    public class App {
        private static SessionFactory sf;
        static{
            sf = new Configuration().configure().buildSessionFactory();
        }
        
        @Test
        public void setOperation(){
            Session s = sf.openSession();
            s.beginTransaction();
            
            /*
             * Set:保存带Set的集合
             */
            User user = new User();
            user.setUserId(2);
            user.setUserName("孙五");
            Set<String> email = new HashSet<>();
            email.add("c@a.com");
            email.add("d@b.com");
            user.setUserEmail(email);
            
            /*
             * List:保存List
             */
            user.getUserPhoneNumber().add("189898989");
            user.getUserPhoneNumber().add("108080808");
            
            /*
             * Map:保存Map
             */
            user.getUserAddress().put("上海", "浦东");
            user.getUserAddress().put("杭州", "西湖");
            
            s.save(user);
            
            s.getTransaction().commit();
            s.close();
            sf.close();    
            
        }
    }
    
    
    

    目录

    3.集合数据的读取

    集合数据的读取采用懒加载方式:当映射正确的时候,使用到相关集合数据,hibernate才会想数据库发送执行语句
    Demo:
    将上述例子中的App类中增加读取函数

    @Test
        public void GetCollection(){
            Session s = sf.openSession();
            s.beginTransaction();
            
            User user = (User) s.get(User.class, 4);
            System.out.println("查询到用户的信息:");
            System.out.println("用户ID:" + user.getUserId());
            System.out.println("用户名字:" + user.getUserName());
            
            /*
             * 懒加载:当有正确的映射时候,只有当使用集合相关数据时候,hibernate才会想数据库发送相关语句
             */
            System.out.println("用户邮箱:" + user.getUserEmail());
            System.out.println("用户电话: " + user.getUserPhoneNumber());
            System.out.println("用户地址: " + user.getUserAddress());
            
            s.getTransaction().commit();
            s.close();
            sf.close();    
        }  
    
    

    可以得到结果:

    查询到用户的信息:
    用户ID:4
    用户名字:孙五
    用户邮箱:[d@b.com, c@a.com]
    用户电话: [189898989, 108080808]
    用户地址: {上海=浦东, 杭州=西湖}


    目录

    4.一对多和多对一映射

    4.1概念

    实际开发中,有很多情况例如上面的主数据类中保存了子数据类的对象,当时常常这个集合对象内容不是单一的基本数据类型,需要用对象方式来保存更多的数据。这个时候就存在了一对多和多对一的映射关系

    4.2配置和开发

    4.2.1关键点

    配置的关键在于对主数据类和子数据类都可以配置对应的配置文件:

    • 单向关联:配置一对多
    • 单向关联:配置多对一
    • 双向关联:配置上面两种单向关联均配置
      注意:配置了哪一种情况,就可以根据哪一种情况来操作数据。也就是说配置了一对多则可以通过一来维护多(保存时候保存一关联保存多),配置了多对一则可以通过多来维护一(保存时候保存多关联保存一)。因此在使用时候,为了提高效率,建议先保存一的一方再去保存多,因为反过来的话执行一次insert后还要多执行一次update,会降低执行效率!

    4.2.2实例

    • 有数据关系:

    • 编写主数据类和子数据类:

    package per.liyue.code.hibernate_multimapping;
    import java.util.HashSet;
    import java.util.Set;
    /*
     * 主数据类对象,包含了一个集合类型的属性,内容是另一个类的对象
     */
    public class Department {
        private int depId;
        private String depName;
        private Set<Employee> employee = new HashSet<Employee>();
        public int getDepId() {
            return depId;
        }
        public void setDepId(int depId) {
            this.depId = depId;
        }
        public String getDepName() {
            return depName;
        }
        public void setDepName(String depName) {
            this.depName = depName;
        }
        public Set<Employee> getEmployee() {
            return employee;
        }
        public void setEmployee(Set<Employee> employee) {
            this.employee = employee;
        }
    }
    
    package per.liyue.code.hibernate_multimapping;
    /*
     * 子数据类,这个类的对象是主数据类的集合元素
     */
    public class Employee {
        private int empId;
        public int getEmpId() {
            return empId;
        }
        public void setEmpId(int empId) {
            this.empId = empId;
        }
        
        private String empName;
        public String getEmpName() {
            return this.empName;
        }
        public void setEmpName(String empName) {
            this.empName = empName;
        }
        
        
        //多对一:
        private Department dept;
        public Department getDept() {
            return dept;
        }
        public void setDept(Department dept) {
            this.dept = dept;
        }
        
    }
       
    
    
    • 配置两个类的配置文件
      • 一对多的配置
    <!-- 主数据类的配置文件 -->
    <set name="主数据类中的子数据类的类对象" table="子数据类的表名称">
          <key column="主数据类的主键(也就是子数据类的外键)"></key>
          <one-to-many class="子数据类的类名称,注意同一个包下可以不带包名称,注意不要在不同包下重复用一个类名称"/>
    </set>  
    
    
    * 多对一的配置
    
    <!-- 子数据类的配置文件 -->
    
    <many-to-one name="子数据类中的主数据类对象" column="子数据类的外键(主数据类的主键)" class="主数据类名称"></many-to-one>  
    
    
    • Demo:
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
    <!-- package:类对象所在的包
         auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
         Demo:在true时候可以写为session.createQuery("from Employee").list();
                   在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
     -->
    <hibernate-mapping package="per.liyue.code.hibernate_multimapping" auto-import="true">
        <class name="Department" table="Department">
            <!-- 主键 -->
            <id name="depId" column="dep_id" >
                <generator class="native" />            
            </id>
            
            <property name="depName" column="dep_name"></property>
            
            <!-- 设置一对多关系:
                name:集合中的类对象对应的类
                table:集合中类对象对应的表
                key:子数据类中对应外键
                one-to-many:子数据类对应的类,如果是同一个包下的类可以不写包名
             -->
            <set name="employee" table="Employee">
                <key column="dep_id"></key>
                <one-to-many class="Employee"/>
            </set>
            
            
            
        </class>
    </hibernate-mapping>  
    
    
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
    <!-- package:类对象所在的包
         auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
         Demo:在true时候可以写为session.createQuery("from Employee").list();
                   在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
     -->
    <hibernate-mapping package="per.liyue.code.hibernate_multimapping" auto-import="true">
        <class name="Employee" table="Employee">
            <!-- 主键 -->
            <id name="empId" column="emp_id" >
                <generator class="native" />            
            </id>
            
            <property name="empName" column="emp_name"></property>
            
            <!-- 设置多对一关系:
                name:映射的主类对象
                column:外键的字段名称
                class:映射主类
             -->
            <many-to-one name="dept" column="dep_id" class="Department"></many-to-one>
            
        </class>
    </hibernate-mapping>  
    
    
    • 执行语句
    package per.liyue.code.hibernate_multimapping;
    
    
    import java.util.HashSet;
    import java.util.Set;
    
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.junit.Test;
    
    
    public class App_Save {
    	private static SessionFactory sf;
    	static{
    		sf = new Configuration().configure().buildSessionFactory();
    	}
    	
    	@Test
    	/*
    	* 一维护多,无论保存时候先保存部门还是后保存部门,必须要多执行相应的update语句保证id一致。
    	*/
    	public void DemoOne2Many(){
    		Session s = sf.openSession();
    		s.beginTransaction();
    		
    		Department dept = new Department();
    		dept.setDepName("硬件开发部");
    		
    		Employee zhangSan = new Employee();
    		zhangSan.setEmpName("王五");
    		
    		Employee liSi = new Employee();
    		liSi.setEmpName("赵二");
    		
    		/*
    		*这里的映射关系是一对多,也就是通过部门来维护员工 
    		*/	
    		dept.getEmployee().add(zhangSan);
    		dept.getEmployee().add(liSi);		
    		
    		s.save(zhangSan);
    		s.save(liSi);
    		s.save(dept);
    		
    		
    		s.getTransaction().commit();
    		s.close();
    		sf.close();	
    		
    	}
    	
    	@Test
    	/*
    	* 推荐方式:通过多来维护一,这样高效!
    	*/
    	public void DemoMany2One(){
    		Session s = sf.openSession();
    		s.beginTransaction();
    		
    		Department dept = new Department();
    		dept.setDepName("软件开发部");
    		
    		Employee zhangSan = new Employee();
    		zhangSan.setEmpName("张三");
    		
    		Employee liSi = new Employee();
    		liSi.setEmpName("李四");
    		
    		/*
    		*这里的映射关系是多对一,也就是通过员工来维护部门 
    		*/	
    		zhangSan.setDept(dept);
    		liSi.setDept(dept);
    		
    		//这个时候如果部门保存在后面,则保存员工时候没有部门编号,会增加两条update语句
    		s.save(dept);
    		s.save(zhangSan);
    		s.save(liSi);
    		
    		
    		s.getTransaction().commit();
    		s.close();
    		sf.close();	
    		
    	}
    		
    }
    
    
    

    执行的语句结果

    一对多的情况:
    Hibernate: insert into Employee (emp_name, dep_id) values (?, ?)
    Hibernate: insert into Employee (emp_name, dep_id) values (?, ?)
    Hibernate: insert into Department (dep_name) values (?)
    Hibernate: update Employee set dep_id=? where emp_id=?
    Hibernate: update Employee set dep_id=? where emp_id=?
    多对一的情况:
    Hibernate: insert into Department (dep_name) values (?)
    Hibernate: insert into Employee (emp_name, dep_id) values (?, ?)
    Hibernate: insert into Employee (emp_name, dep_id) values (?, ?)

    在hibernate中唯一的方式把对象映射为外键的方式:many-to-one
    建议通过多对一来维护,这样操作高效!

    • 读取数据
      • 懒加载:在执行的时候hibernate才发送并执行相关SQL语句
    package per.liyue.code.hibernate_multimapping;
    
    
    import java.util.HashSet;
    import java.util.Set;
    
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.junit.Test;
    
    
    public class App_Get {
    	private static SessionFactory sf;
    	static{
    		sf = new Configuration().configure().buildSessionFactory();
    	}
    	
    	@Test
    	/*
    	* 一对多和多对一的读取
    	*/
    	public void DemoOne2Many(){
    		Session s = sf.openSession();
    		s.beginTransaction();
    		
    		Department dep = (Department)s.get(Department.class, 1);
    		System.out.println("从部门读取:" + dep.getDepId());
    		/*
    		* 懒加载:不执行下面的调用,hibernate不会向数据库发送相关语句并执行
    		*/
    		System.out.println("从部门读取:" + dep.getEmployee());
    		
    		Employee emp = (Employee)s.get(Employee.class, 2);
    		System.out.println("从员工读取:" + emp.getEmpName());
    		System.out.println("从员工读取:" + emp.getDept());
    		
    		
    		s.getTransaction().commit();
    		s.close();
    		sf.close();	
    		
    	}
    }
    
    
    

    目录

    5.反转:inverse

    5.1概念

    • 表示反转控制,取消控制
    • 在一对多和多对一的关系中,一的一方可以设置inverse属性。

    5.2实例

    5.2.1配置

    在上面的Department.hbm.xml中,在一对多的映射中可以设定:

    <set name="employee" table="Employee" inverse="false">
                <key column="dep_id"></key>
                <one-to-many class="Employee"/>
            </set>  
    
    

    这里的false是默认值,表示主数据类有控制权限,如果设置为true则表示没有控制权限

    5.2.2影响

    • 保存:有影响,解除关联后,子数据类依旧会保存,但是外键关联取消,保存为NULL
    • 读取:无影响
    • 解除关联关系:有影响,解除关联关系的用法是先读取,然后主类调用clear()方法。如果解除,则则不能解除关系,但是不报错
    • 删除:有影响,解除后如果外键有值,删除会违反主外键约束而报错,如果外键没有值为NULL,则可以删除

    目录

    6.级联:cascade

    6.1概念

    级联操作的设置,在一对多和多对一均可配置。如在配置文件中:

    <set name="employee" table="Employee" inverse="false" cascade="none">
                <key column="dep_id"></key>
                <one-to-many class="Employee"/>
    </set>  
    
    

    6.2配置

    只在一对多一方配置
    级联操作有以下几种配置:

    • none:默认值,不级联操作
    • save-update:设置级联保存和更新。注意:save和update不能拆分使用
    • save-update,delete:设置级联保存、更新和删除
    • all: 全部

    6.3inserse和cascade区别

    不能在一起使用


    目录

    7.多对多映射

    7.1关系

    在实际应用中有多对多的映射关系:

    不同的人有不同的角色,不同的角色对应多个人。在数据库中二者的关联关系通常放到另一个表中。形成了多对多映射

    7.2配置和实现

    7.2.1定义两个数据类

    package per.liyue.code.hibernate_mu2mu;
    
    
    import java.util.HashSet;
    import java.util.Set;
    /*
     * 数据类角色
     */
    public class Role {
    	private int roleId;
    	private String roleName;
    	
    	//包含另一个数据类对象
    	private Set<Person> person = new HashSet<>();
    	
    	public int getRoleId() {
    		return roleId;
    	}
    	public void setRoleId(int roleId) {
    		this.roleId = roleId;
    	}
    	public String getRoleName() {
    		return roleName;
    	}
    	public void setRoleName(String roleName) {
    		this.roleName = roleName;
    	}
    	public Set<Person> getPerson() {
    		return person;
    	}
    	public void setPerson(Set<Person> person) {
    		this.person = person;
    	}
    }
    
    
    
    
    
    

    7.2.2配置二者的映射关系

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
    <!-- package:类对象所在的包
         auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
         Demo:在true时候可以写为session.createQuery("from Employee").list();
                   在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
     -->
    <hibernate-mapping package="per.liyue.code.hibernate_mu2mu" auto-import="true">
        <class name="Role" table="Role">
            <!-- 主键 -->
            <id name="roleId" column="r_id" >
                <generator class="native" />            
            </id>
            
            <property name="roleName" column="r_name"></property>
            
            <!-- 设置多对多关系:
                name:
             -->
            <set name="person" table="Reletionship" inverse="false" cascade="none">
                <key column="r_id"></key>
                <many-to-many column="per_id" class="Person"></many-to-many>
            </set>
            
            
            
        </class>
    </hibernate-mapping>  
    
    
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
    <!-- package:类对象所在的包
         auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
         Demo:在true时候可以写为session.createQuery("from Employee").list();
                   在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
     -->
    <hibernate-mapping package="per.liyue.code.hibernate_mu2mu" auto-import="true">
        <class name="Person" table="Person">
            <!-- 主键 -->
            <id name="personId" column="per_id" >
                <generator class="native" />            
            </id>
            
            <property name="personName" column="per_name"></property>
            
            <!-- 设置多对多关系:
                name:另一个类对象的实例名称
                talbe:二者关系的数据库映射表
                key-column:当前类的主键,关系表的外键
                many-to-mangy-column:另一个类的主键,关系表中的另一个外键
                many-to-mangy-class:另一个类的类名称
             -->
            <set name="role" table="Reletionship" inverse="false" cascade="none" >
                <key column="per_id"></key>
                <many-to-many column="r_id" class="Role"></many-to-many>
            </set>
            
            
            
        </class>
    </hibernate-mapping>  
    
    

    7.2.3实现业务

    package per.liyue.code.hibernate_mu2mu;
    
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.junit.Test;
    
    
    import per.liyue.code.hibernate_multimapping.Department;
    import per.liyue.code.hibernate_multimapping.Employee;
    
    
    public class App {
    	private static SessionFactory sf;
    	static{
    		sf = new Configuration().configure().buildSessionFactory();
    	}
    	
    	@Test
    	/*
    	* 
    	*/
    	public void DemoMany2Many(){
    		Session s = sf.openSession();
    		s.beginTransaction();
    		
    		//创建
    		Person p_zhangsan = new Person();
    		p_zhangsan.setPersonName("张三");		
    		Person p_lisi = new Person();
    		p_lisi.setPersonName("李四");
    		
    		Role r_teacher = new Role();
    		r_teacher.setRoleName("教师");
    		Role r_student = new Role();
    		r_student.setRoleName("学生");
    		Role r_developer = new Role();
    		r_developer.setRoleName("开发");
    		
    		//关系
    		p_zhangsan.getRole().add(r_teacher);
    		p_zhangsan.getRole().add(r_developer);
    		
    		p_lisi.getRole().add(r_student);
    		
    		//保存
    		s.save(p_zhangsan);
    		s.save(p_lisi);
    		s.save(r_teacher);
    		s.save(r_student);
    		s.save(r_developer);
    		
    		s.getTransaction().commit();
    		s.close();
    		sf.close();	
    		
    	}
    }
    
    
    

    8.映射关系配置总结

    • 一对多:
    
    <set name="映射的集合属性" table="(可选)集合属性对应的外键表">
        <key column="外键表的,外键字段" />
        <one-to-many class="集合元素的类型" />
    </set>
    
    • 多对一:
    
    <many-to-one name="对象属性" class="对象类型" column="外键字段字段" />
    
    • 多对多
    
    <set name="" table="">
        <key column="" />
        <many-to-many column="" class="">
    </set>    
    
    

    目录

    8.一对一映射

    8.1分类

    可以有两种一对一映射:

    • 基于外键,外键唯一
    • 基于主键
      假设有用户和身份证的一一映射,可以有下面的两种数据库表关系

    那么两种模型下的实例为:

    8.2有主键的映射

    8.2.1类对象

    
    
    
    
    
    

    8.2.2配置文件

    
    
    
    
    
    
    
    
    
    

    8.2.3主配置和实现

    
    
    
    
    
    
    
    

    8.3无主键的映射

    8.3.1类对象

    
    
    
    
    
    

    8.3.2配置文件

    
    
    
    
    
    
    
    
    
    

    8.3.3主配置和实现

    
    
    
    
    
    
    
    

    目录

    9.组件映射

    9.1适用范围

    • 组件映射指的是一个类中包含了另一个类的对象。是包含与被包含的概念
    • 映射会将两个类映射到一个表中

    9.2实例

    9.2.1类

    package per.liyue.code.component_demo;/** * Created by liyue on 2016/10/21. */public class User{    private int id;    private String name;    private Wheel wheel;}```
    
    
    ```java
    package per.liyue.code.component_demo;/** * Created by liyue on 2016/10/21. */public class Wheel{    private int count;    public int getCount()    {        return count;    }    public void setCount(int count)    {        this.count = count;    }    public int getSize()    {        return size;    }    public void setSize(int size)    {        this.size = size;    }    private int size;}```
    
    
    ## 9.2.2配置文件
    ```xml
    <?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 --><!-- package:类对象所在的包     auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:     Demo:在true时候可以写为session.createQuery("from Employee").list();               在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list(); --><hibernate-mapping package="per.liyue.code.component_demo.User" auto-import="true">    <class name="User" table="t_User">        <!-- 主键 -->        <id name="id" column="user_id" >            <generator class="native" />        </id>        <property name="name" column="user_name"></property>        <!--        组件关系        -->        <component name="wheel">            <!--组件成员-->            <property name="count"></property>            <property name="size"></property>        </component>    </class></hibernate-mapping>```
    
    
    
    
    ---
    [toc]
    ---
    
    
    # 10.继承映射
    ## 10.1概念
    ### 10.1.1简单继承
    有多少个子类写多少个配置文件
    

    // 动物类
    public abstract class Animal {

    private int id;
    private String name;
    
    <class name="Cat" table="t_Cat">
    	<!-- 简单继承映射: 父类属性直接写 -->
    	<id name="id">
    		<generator class="native"></generator>
    	</id>
    	<property name="na"></property>
    	<property name="catchMouse"></property>					 
    </class>
    

    @Test
    public void getSave() {

    	Session session = sf.openSession();
    	session.beginTransaction();
    	
    	// 保存
    

    // Cat cat = new Cat();
    // cat.setName("大花猫");
    // cat.setCatchMouse("抓小老鼠");
    // session.save(cat);

    	// 获取时候注意:当写hql查询的使用,通过父类查询必须写上类的全名
    	Query q = session.createQuery("from cn.itcast.e_extends1.Animal");
    	List<Animal> list = q.list();
    	System.out.println(list);
    	
    	session.getTransaction().commit();
    	session.close();
    	
    }
    
    
    
    
    
    ### 10.1.2复杂继承
    * 多个子类共用一个表 
    不推荐使用,因为违反数据库设计原则。在子类数量众多且属性单一情况下适用。
    
    
    
    * 每个子类用一个表
    
    
    
    * 父类不对应表
    
     
    
    
    ## 10.2实例
  • 相关阅读:
    Git远程仓库的使用(github为例)
    SQL查看数据库中每张表的数据量和总数据量
    HTML简单的注册页面搭建
    java新建日期获取工具
    ArrayList的使用方法技巧(转载)
    UI初级 TextField
    UI初级 Label
    UI入门 纯代码 第一节 UIWindow, UIView
    C 入门 第十一节
    secoclient安装mac版提示系统配置文件写入失败的解决方案
  • 原文地址:https://www.cnblogs.com/bugstar/p/8512845.html
Copyright © 2020-2023  润新知