• Hibernate学习---第七节:关联关系


    一、关联关系一对一外键(双向)

    1、实体类,代码如下:

    package learn.hibernate.bean;
    
    import java.util.Date;
    
    /**
     * 持久化类设计
     * 注意:
     *         持久化类通常建议要有一个持久化标识符(ID)
     *         持久化标识符通常建议使用封装类(例如:Integer  因为基本类型存在默认值)
     *         持久化类通常建议手动添加一个无参构造函数 (因为有些操作是通过放射机制进行的)
     *         属性通常建议提供  getter/setter 方法
     *         持久化类不能使用 final 修饰
     *         持久化类中如果使用了集合类型数据,只能使用集合所对应的接口类型来声明(List/Map/Set)
     *              如下:ArrayList list = new ArrayList();  不行
     *                 List list = new ArrayList(); 可行
     */
    public class Person {
    
        private Integer id;
        private String name;
        private int age;
        private int passwork;
        private Date birthday;
        
        private Address addres;
        
        public Person() {
            
        }
        
        public Person(String name, int age, int passwork, Date birthday) {
            super();
            this.name = name;
            this.age = age;
            this.passwork = passwork;
            this.birthday = birthday;
        }
        
        @Override
        public String toString() {
            return "Person [id=" + id + ", name=" + name + ", age=" + age
                    + ", passwork=" + passwork + ", birthday=" + birthday + "]";
        }
        
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public int getPasswork() {
            return passwork;
        }
        public void setPasswork(int passwork) {
            this.passwork = passwork;
        }
        public Date getBirthday() {
            return birthday;
        }
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public Address getAddres() {
            return addres;
        }
    
        public void setAddres(Address addres) {
            this.addres = addres;
        }
        
    }
    package learn.hibernate.bean;
    
    public class Address {
    
        private Integer id;
        private String zipCode;
        private String address;
        private Person person;
        
        public Address() {
            super();
        }
        
        public Address(String zipCode, String address) {
            super();
            this.zipCode = zipCode;
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "Address [zipCode=" + zipCode + ", address=" + address + "]";
        }
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getZipCode() {
            return zipCode;
        }
        public void setZipCode(String zipCode) {
            this.zipCode = zipCode;
        }
        public String getAddress() {
            return address;
        }
        public void setAddress(String address) {
            this.address = address;
        }
    
        public Person getPerson() {
            return person;
        }
    
        public void setPerson(Person person) {
            this.person = person;
        }
    }

    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">
    <hibernate-mapping package="learn.hibernate.bean">
        <class name="Person" table="t_person">
            <id name="id" column="person_id">
                <generator class="native"/>
            </id>
            <property name="name" column="t_name"/>
            <property name="age"/>    
            <property name="passwork"/>
            <property name="birthday"/>
            <!-- 
                one-to-one 表示一对一的配置
                name 指定 Person 类中的关联关系的 address 属性
                cascade 表示级联操作
                    级联是对象之间的关联操作,只影响添加、删除、更新,不影响查询
                    all:所有情况下都进行关联操作(save、update、delete)
                    none:所有情况下都不进行关联操作(默认值)
                    save-update:在执行 (save、update、saveOrUpdate)进行关联操作
                    delete:在执行 delete 时进行关联操作
             -->
            <one-to-one name="addres" cascade="all"/>
        </class>
        <class name="Address" table="t_address">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="zipCode"/>
            <property name="address"/>
            <!-- 
                基于外键的一对一配置,在从表一端使用 many-to-one 
                name Address类中关联关系 Person 类的引用变量名
                column 指定外键列名,可选
                unique 唯一约束,因为使用的是一对一外键关联
                not-null 指定列是否为空
             -->
            <many-to-one name="person" column="person_id" unique="true" not-null="true"/>
        </class>
    </hibernate-mapping>

    3、测试类,代码如下:

    package learn.hibernate.test;
    
    import static org.junit.Assert.*;
    
    import java.util.Date;
    
    import learn.hibernate.bean.Address;
    import learn.hibernate.bean.Person;
    import learn.hibernate.bean.Phones;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.service.ServiceRegistry;
    import org.hibernate.service.ServiceRegistryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    public class TestHibernate {
    
        SessionFactory factory = null;
        Session session = null;
        Transaction tx = null;
        
        /**
         * 测试之前初始化数据
         * @throws Exception
         */
        @SuppressWarnings("deprecation")
        @Before
        public void setUp() throws Exception {
            System.out.println("---------初始化数据----------");
            
            Configuration config = new Configuration().configure();
            ServiceRegistry sr = new ServiceRegistryBuilder()
            .applySettings(config.getProperties()).buildServiceRegistry();
            factory = config.buildSessionFactory(sr);
            session = factory.openSession();
        }
    
        /**
         * 测试之后释放(销毁)数据
         * @throws Exception
         */
        @After
        public void tearDown() throws Exception {
            System.out.println("---------释放数据----------");
            if(session.isOpen()){
                session.close();
            }
        }
        
        @Test
        public void testAdd(){
            Person p = new Person("tiger",22,123456,new Date());
            Address address = new Address("410000","湖南长沙");
            p.setAddres(address);
            address.setPerson(p);
            
            tx = session.beginTransaction();
            // 进行数据保存的时候先持久化主表,在持久化从表;否则会执行 update 语句
            session.persist(p);
            session.persist(address);
            tx.commit();
        }
        
        /**
         * 通过主表获取数据
         * 通过 left outer join 进行数据查询
         */
        @Test
        public void testGet(){
            Person p = (Person)session.get(Person.class, 1);
            System.out.println(p);
            System.out.println("------------------------");
            System.out.println(p.getAddres());
        }
        
        /**
         * 通过从表获取数据
         * 先查询从表数据,获取主表数据时再通过 left outer join 进行数据查询
         */
        @Test
        public void testGet2(){
            Address address = (Address)session.get(Address.class, 1);
            System.out.println(address);
            System.out.println("------------------------");
            System.out.println(address.getPerson());
        }
        
        /**
         * 更新
         */
        @Test
        public void testUpdate(){
            Person p = (Person)session.get(Person.class, 2);
            p.setAge(25);
            Address address = p.getAddres();
            address.setAddress("湖北武汉");
            tx = session.beginTransaction();
            session.merge(p);
            tx.commit();
        }
        
        /**
         * 删除
         */
        @Test
        public void testDel(){
            tx = session.beginTransaction();
            Person p = (Person)session.get(Person.class, 1);
            session.delete(p);
            tx.commit();
        }
    }

    4、测试

    (1)、测试 testAdd(),控制台打印:

    QQ截图20141217210833

    (2)、测试 testGet(),控制台打印:

    QQ截图20141217210929

    (3)、测试 testGet2(),控制台打印:

    QQ截图20141217211012

    (4)、测试 testUpdate(),控制台打印:

    QQ截图20141217212434

    (5)、测试 testDel(),控制台打印:

    QQ截图20141217211733

    如果映射配置文件没有添加  cascade="all" 或者  cascade="delete",删除的时候会报如下错误:

    org.hibernate.exception.ConstraintViolationException: could not execute statement
        at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:72)
        at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
        at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
        at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
        at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:211)
        at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:62)
        at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3400)
        at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3630)
        at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:114)
        at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
        at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
        at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
        at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
        at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
        at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
        at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
        at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
        at learn.hibernate.test.TestHibernate.testDel(TestHibernate.java:115)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
    Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`hibernate`.`t_address`, CONSTRAINT `FK_sydlu68t7mra095us6fku8eyt` FOREIGN KEY (`person_id`) REFERENCES `t_person` (`person_id`))
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
        at com.mysql.jdbc.Util.getInstance(Util.java:386)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1039)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3609)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3541)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2002)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2163)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2624)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2127)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2427)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2345)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2330)
        at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
        ... 38 more

    三、关联关系一对一主键(双向)

    除了配置文件不一样之外,其他的都是一样的;配置文件代码如下:

    <?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">
    <hibernate-mapping package="learn.hibernate.bean">
        <class name="Person" table="t_person">
            <id name="id" column="person_id">
                <generator class="native"/>
            </id>
            <property name="name" column="t_name"/>
            <property name="age"/>    
            <property name="passwork"/>
            <property name="birthday"/>
            <one-to-one name="addres" cascade="all"/>
        </class>
        <class name="Address" table="t_address">
            <id name="id">
                <!-- 表示adderss的主键不再由 自己产生,而是使用Person对应表的主键 -->
                <generator class="foreign">
                    <param name="property">person</param>
                </generator>
            </id>
            <property name="zipCode"/>
            <property name="address"/>
            <!-- 
                基于 主键 的 一对一 双向 关联 
                constrained 表示主键约束 true表示启用主键约束
            -->
            <one-to-one name="person" constrained="true"/>
        </class>
    </hibernate-mapping>

    四、关联关系一对多(双向)

    1、实体类,代码如下:

    package learn.hibernate.bean;
    
    import java.util.Date;
    import java.util.HashSet;
    import java.util.Set;
    
    /**
     * 持久化类设计
     * 注意:
     *         持久化类通常建议要有一个持久化标识符(ID)
     *         持久化标识符通常建议使用封装类(例如:Integer  因为基本类型存在默认值)
     *         持久化类通常建议手动添加一个无参构造函数 (因为有些操作是通过放射机制进行的)
     *         属性通常建议提供  getter/setter 方法
     *         持久化类不能使用 final 修饰
     *         持久化类中如果使用了集合类型数据,只能使用集合所对应的接口类型来声明(List/Map/Set)
     *              如下:ArrayList list = new ArrayList();  不行
     *                 List list = new ArrayList(); 可行
     */
    public class Person {
    
        private Integer id;
        private String name;
        private int age;
        private int passwork;
        private Date birthday;
        
        private Set<Address> addres = new HashSet<Address>();
        
        public Person() {
            
        }
        
        public Person(String name, int age, int passwork, Date birthday) {
            super();
            this.name = name;
            this.age = age;
            this.passwork = passwork;
            this.birthday = birthday;
        }
        
        @Override
        public String toString() {
            return "Person [id=" + id + ", name=" + name + ", age=" + age
                    + ", passwork=" + passwork + ", birthday=" + birthday + "]";
        }
        
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public int getPasswork() {
            return passwork;
        }
        public void setPasswork(int passwork) {
            this.passwork = passwork;
        }
        public Date getBirthday() {
            return birthday;
        }
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public Set<Address> getAddres() {
            return addres;
        }
    
        public void setAddres(Set<Address> addres) {
            this.addres = addres;
        }
    }

    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">
    <hibernate-mapping package="learn.hibernate.bean">
        <class name="Person" table="t_person">
            <id name="id" column="person_id">
                <generator class="native"/>
            </id>
            <property name="name" column="t_name"/>
            <property name="age"/>    
            <property name="passwork"/>
            <property name="birthday"/>
            <!-- 
                通过Set配置一个人对应的多个地址的关联关系
                inverse=true 表示在Person端不维护关系;因为多的一端有外键,管理关联关系更高效
             -->
            <set name="addres" cascade="all" inverse="true">
                <!-- 指定 addres 集合中的数据对应t_person的的一个外键 -->
                <key column="p_id"/>
                <!-- 指定Person 关联的实例类型 -->
                <one-to-many class="Address"/>
            </set>
            
            <!-- inverse="false" 一定要为 false 因为要控制顺序 -->
            <!-- <list name="addres" inverse="false" cascade="all">
                <key column="p_id"/>
                <index column="indexs" type="integer"/>
                <one-to-many class="Address"/>
            </list> -->
            <!-- inverse="false" 一定要为 false 因为要控制顺序 -->
            <!-- <map name="addres" inverse="false" cascade="all">
                <key column="p_id"/>
                <index column="map_key" type="string"/>
                <one-to-many class="Address"/>
            </map> -->
        </class>
        <class name="Address" table="t_address">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="zipCode"/>
            <property name="address"/>
            <!-- 
                多的一端使用 many-to-one 进行配置 
            -->
            <many-to-one name="person" column="p_id"/>
        </class>
    </hibernate-mapping>

    3、测试代码,如下:

    package learn.hibernate.test;
    
    import static org.junit.Assert.*;
    
    import java.util.Date;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    import learn.hibernate.bean.Address;
    import learn.hibernate.bean.Person;
    import learn.hibernate.bean.Phones;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.service.ServiceRegistry;
    import org.hibernate.service.ServiceRegistryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    public class TestHibernate {
    
        SessionFactory factory = null;
        Session session = null;
        Transaction tx = null;
        
        /**
         * 测试之前初始化数据
         * @throws Exception
         */
        @SuppressWarnings("deprecation")
        @Before
        public void setUp() throws Exception {
            System.out.println("---------初始化数据----------");
            
            Configuration config = new Configuration().configure();
            ServiceRegistry sr = new ServiceRegistryBuilder()
            .applySettings(config.getProperties()).buildServiceRegistry();
            factory = config.buildSessionFactory(sr);
            session = factory.openSession();
        }
    
        /**
         * 测试之后释放(销毁)数据
         * @throws Exception
         */
        @After
        public void tearDown() throws Exception {
            System.out.println("---------释放数据----------");
            if(session.isOpen()){
                session.close();
            }
        }
        
        @Test
        public void testAdd(){
            Person p = new Person("tiger",22,123456,new Date());
            Address address1 = new Address("410000","湖南长沙");
            Address address2 = new Address("410001","湖南郴州");
            Address address3 = new Address("410002","湖南常德");
            Address address4 = new Address("410003","湖南衡阳");
            
            Set<Address> set = new HashSet<Address>();
            
            set.add(address1);
            set.add(address2);
            set.add(address3);
            set.add(address4);
            
            // person 与多个 Address 建立关联
            p.setAddres(set);
            // Address 与 person 建立关联;如果不建立关联,那么外键为 null
            address1.setPerson(p);
            address2.setPerson(p);
            address3.setPerson(p);
            address4.setPerson(p);
            
            tx = session.beginTransaction();
            session.persist(p);
            tx.commit();
        }
        
        /**
         * 通过主表获取数据
         * 通常从表的数据时延迟查询
         */
        @Test
        public void testGet(){
            Person p = (Person)session.get(Person.class, 1);
            System.out.println(p);
            System.out.println("------------------------");
            Iterator<Address> it = p.getAddres().iterator();
            while(it.hasNext()){
                Address address = it.next();
                System.out.println(address);
            }
        }
        
        /**
         * 通过从表获取数据
         * 先查询从表数据,主表数据是延迟查询
         */
        @Test
        public void testGet2(){
            Address address = (Address)session.get(Address.class, 1);
            System.out.println(address);
            System.out.println("------------------------");
            System.out.println(address.getPerson());
        }
        
        /**
         * 删除主表时,会将所对应的从表数据删除
         */
        @Test
        public void testDel(){
            tx = session.beginTransaction();
            Person p = (Person)session.get(Person.class, 1);
            session.delete(p);
            tx.commit();
        }
        
        /**
         * 删除从表数据,只会删除从表自己的数据
         */
        @Test
        public void testDel2(){
            tx = session.beginTransaction();
            Address address = (Address)session.get(Address.class, 5);
            session.delete(address);
            tx.commit();
        }
    }

    五、关联关系多对多(双向)

    1、实体类,代码如下:

    package learn.hibernate.bean;
    
    import java.util.Date;
    import java.util.HashSet;
    import java.util.Set;
    
    /**
     * 持久化类设计
     * 注意:
     *         持久化类通常建议要有一个持久化标识符(ID)
     *         持久化标识符通常建议使用封装类(例如:Integer  因为基本类型存在默认值)
     *         持久化类通常建议手动添加一个无参构造函数 (因为有些操作是通过放射机制进行的)
     *         属性通常建议提供  getter/setter 方法
     *         持久化类不能使用 final 修饰
     *         持久化类中如果使用了集合类型数据,只能使用集合所对应的接口类型来声明(List/Map/Set)
     *              如下:ArrayList list = new ArrayList();  不行
     *                 List list = new ArrayList(); 可行
     */
    public class Person {
    
        private Integer id;
        private String name;
        private int age;
        private int passwork;
        private Date birthday;
        
        private Set<Address> addres = new HashSet<Address>();
        
        public Person() {
            
        }
        
        public Person(String name, int age, int passwork, Date birthday) {
            super();
            this.name = name;
            this.age = age;
            this.passwork = passwork;
            this.birthday = birthday;
        }
        
        @Override
        public String toString() {
            return "Person [id=" + id + ", name=" + name + ", age=" + age
                    + ", passwork=" + passwork + ", birthday=" + birthday + "]";
        }
        
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public int getPasswork() {
            return passwork;
        }
        public void setPasswork(int passwork) {
            this.passwork = passwork;
        }
        public Date getBirthday() {
            return birthday;
        }
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public Set<Address> getAddres() {
            return addres;
        }
    
        public void setAddres(Set<Address> addres) {
            this.addres = addres;
        }
    }
    package learn.hibernate.bean;
    
    import java.util.Set;
    
    public class Address {
    
        private Integer id;
        private String zipCode;
        private String address;
        private Set<Person> person;
        
        public Address() {
            
        }
        
        public Address(String zipCode, String address) {
            super();
            this.zipCode = zipCode;
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "Address [zipCode=" + zipCode + ", address=" + address + "]";
        }
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getZipCode() {
            return zipCode;
        }
        public void setZipCode(String zipCode) {
            this.zipCode = zipCode;
        }
        public String getAddress() {
            return address;
        }
        public void setAddress(String address) {
            this.address = address;
        }
    
        public Set<Person> getPerson() {
            return person;
        }
    
        public void setPerson(Set<Person> person) {
            this.person = person;
        }
    }

    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">
    <hibernate-mapping package="learn.hibernate.bean">
        <class name="Person" table="t_person">
            <id name="id" column="person_id">
                <generator class="native"/>
            </id>
            <property name="name" column="t_name"/>
            <property name="age"/>    
            <property name="passwork"/>
            <property name="birthday"/>
            <!-- 
                通过Set配置一个人对应的多个地址的关联关系
                inverse=true 表示在Person端不维护关系;因为多的一端有外键,管理关联关系更高效
             -->
            <set name="addres" cascade="all" inverse="true" table="person_address">
                <!-- 指定 addres 集合中的数据对应t_person的的一个外键 -->
                <key column="p_id"/>
                <!-- 指定Person 关联的实例类型 -->
                <many-to-many class="Address" column="a_id"/>
            </set>
        </class>
        <class name="Address" table="t_address">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="zipCode"/>
            <property name="address"/>
            
            <set name="person" cascade="all" table="person_address">
                <key column="a_id"/>
                <many-to-many class="Person" column="p_id"/>
            </set>
        </class>
    </hibernate-mapping>

    3、测试类,代码如下:

    package learn.hibernate.test;
    
    import static org.junit.Assert.*;
    
    import java.util.Arrays;
    import java.util.Date;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    import learn.hibernate.bean.Address;
    import learn.hibernate.bean.Person;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.service.ServiceRegistry;
    import org.hibernate.service.ServiceRegistryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    public class TestHibernate {
    
        SessionFactory factory = null;
        Session session = null;
        Transaction tx = null;
        
        /**
         * 测试之前初始化数据
         * @throws Exception
         */
        @SuppressWarnings("deprecation")
        @Before
        public void setUp() throws Exception {
            System.out.println("---------初始化数据----------");
            
            Configuration config = new Configuration().configure();
            ServiceRegistry sr = new ServiceRegistryBuilder()
            .applySettings(config.getProperties()).buildServiceRegistry();
            factory = config.buildSessionFactory(sr);
            session = factory.openSession();
        }
    
        /**
         * 测试之后释放(销毁)数据
         * @throws Exception
         */
        @After
        public void tearDown() throws Exception {
            System.out.println("---------释放数据----------");
            if(session.isOpen()){
                session.close();
            }
        }
        
        @Test
        public void testAdd(){
            Person p1 = new Person("tiger",22,123456,new Date());
            Person p2 = new Person("admin",25,123456,new Date());
            
            Set<Person> pset = new HashSet<Person>();
            pset.add(p1);
            pset.add(p2);
            
            Address address1 = new Address("410000","湖南长沙");
            Address address2 = new Address("410001","湖南郴州");
            Address address3 = new Address("410002","湖南常德");
            Address address4 = new Address("410003","湖南衡阳");
            
            Set<Address> set = new HashSet<Address>();
            
            set.add(address1);
            set.add(address2);
            set.add(address3);
            set.add(address4);
            
            // person 与多个 Address 建立关联
            p1.setAddres(set);
            p2.setAddres(set);
            
            // Address 与 person 建立关联;如果不建立关联,那么外键为 null
            address1.setPerson(pset);
            address2.setPerson(pset);
            address3.setPerson(pset);
            address4.setPerson(pset);
            
            tx = session.beginTransaction();
            session.persist(p1);
            session.persist(p2);
            tx.commit();
        }
        
        /**
         * 通过主表获取数据
         * 通常从表的数据时延迟查询
         */
        @Test
        public void testGet(){
            Person p = (Person)session.get(Person.class, 3);
            System.out.println(p);
            System.out.println("------------------------");
            Iterator<Address> it = p.getAddres().iterator();
            while(it.hasNext()){
                Address address = it.next();
                System.out.println(address);
            }
        }
        
        /**
         * 通过从表获取数据
         * 先查询从表数据,主表数据是延迟查询
         */
        @Test
        public void testGet2(){
            Address address = (Address)session.get(Address.class, 9);
            System.out.println(address);
            System.out.println("------------------------");
            Set<Person> pset = address.getPerson();
            Person[] p = new Person[pset.size()];
            pset.toArray(p);
            System.out.println(Arrays.toString(p));
        }
    }

    六、hibernate 的级联操作详解

    cascade属性表明操作是否从父对象级联到被关联的对象,它的取得可以是以下几种:
    none:在保存,删除或修改当前对象时,不对其附属对象(关联对象)进行级联操作。它是默认值。
    save-update:在保存,更新当前对象时,级联保存,更新附属对象(临时对象,游离对象)。
    delete:在删除当前对象时,级联删除附属对象。
    all:所有情况下均进行级联操作,即包含save-update和delete操作。
    delete-orphan:删除和当前对象解除关系的附属对象。

    以上的文字来自:http://blog.csdn.net/owen_008/article/details/4429382

  • 相关阅读:
    react中的生命周期钩子
    vue小知识
    vue发布中的前后端分离和前后端不分离
    vue中的vuex
    vue项目的发布
    stylus解决移动端1像素
    一行代码实现数组去重(ES6)
    详解js中Number()、parseInt()和parseFloat()的区别_javascript技巧
    关于element-ui 的日期时间选择器的超出时间无法选择的设置
    git使用
  • 原文地址:https://www.cnblogs.com/hwlsniper/p/4273150.html
Copyright © 2020-2023  润新知