自关联测试案例
1、创建表
drop table if exists t_category ; create table t_category ( id int(5) primary key , name varchar(150) , position int(2) , parent_id int(5) , foreign key ( parent_id ) references t_category ( id ) ); insert into t_category ( id , name , position , parent_id ) values ( 1001 , '图书音像' , 2 , null ) ; insert into t_category ( id , name , position , parent_id ) values ( 1002 , '小说' , 2 , 1001 ) ; insert into t_category ( id , name , position , parent_id ) values ( 1003 , '教学辅导' , 1 , 1001 ) ; insert into t_category ( id , name , position , parent_id ) values ( 1004 , '计算机' , 3 , 1001 ) ; insert into t_category ( id , name , position , parent_id ) values ( 1005 , '玄幻' , 2 , 1002 ) ; insert into t_category ( id , name , position , parent_id ) values ( 1006 , '言情' , 1 , 1002 ) ; insert into t_category ( id , name , position , parent_id ) values ( 1007 , '武侠' , 3 , 1002 ) ; insert into t_category ( id , name , position , parent_id ) values ( 2001 , '数码产品' , 1 , null ) ; insert into t_category ( id , name , position , parent_id ) values ( 2002 , '手机' , 1 , 2001 ) ; insert into t_category ( id , name , position , parent_id ) values ( 2003 , '电脑' , 2 , 2001 ) ; insert into t_category ( id , name , position , parent_id ) values ( 2004 , '相机' , 3 , 2001 ) ; insert into t_category ( id , name , position , parent_id ) values ( 2005 , '魅族' , 2 , 2002 ) ; insert into t_category ( id , name , position , parent_id ) values ( 2006 , '小米' , 1 , 2002 ) ; insert into t_category ( id , name , position , parent_id ) values ( 2007 , '坚果Pro' , 3 , 2002 ) ;
分类中有一个外键parent_id 来指定父分类,并通过position来指定分类的位置。
2、持久化类
package ecut.self.entity; import java.io.Serializable; import java.util.List; public class Category implements Serializable { private static final long serialVersionUID = 4807135047518624567L; /** 对象标识符属性 ( 属性值就是 对象标识符 ( Object Identifier ) )*/ private Integer id ; /** 分类的名称 */ private String name ; /** 将来在 界面 中显示时的位置*/ private int position ; /** 先 把 当前的分类 对象 当作 一个 父分类来对待 ,那么它可能对应 多个 子分类 */ private List<Category> categories ; // 维护 从 父分类( one ) 到 子分类 ( many ) 的 一对多 关联关系 /** 再 把 当前分类对象 当作一个 子分类来对待,那么它可能有一个 父分类 */ private Category parent ; // 维护 从 子分类 ( many ) 到 父分类( one ) 的 多对一 关联关系 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 getPosition() { return position; } public void setPosition(int position) { this.position = position; } public List<Category> getCategories() { return categories; } public void setCategories(List<Category> categories) { this.categories = categories; } public Category getParent() { return parent; } public void setParent(Category parent) { this.parent = parent; } }
3、映射文件
<?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="ecut.self.entity.Category" table="t_category"> <id name="id" type="integer" column="id" > <!-- <generator class="increment" /> --> </id> <property name="name" type="string" column="name" /> <property name="position" type="int" column="position" /> <!-- 先 把 当前的分类 对象 当作 一个 父分类来对待 ,那么它可能对应 多个 子分类 --> <list name="categories" cascade="all"> <key column="parent_id" /> <!-- list是有顺序的,下标从0开始 , 添加在第一个子类的时候放在list下标为1的位置上,即position从1开始--> <!-- <index base="1" column="position" /> --> <list-index base="1" column="position" /> <!-- 指定 对方 ( many 一方 ) 的类型 ( List 集合中存放的元素的类型 ) --> <one-to-many class="ecut.self.entity.Category" /> </list> <!-- 再 把 当前分类对象 当作一个 子分类来对待,那么它可能有一个 父分类 --> <!-- 维护从 子分类 ( many ) 到 父分类( one ) 的 多对一 关联 --> <many-to-one cascade="all" name="parent" class="ecut.self.entity.Category" column="parent_id" /> </class> </hibernate-mapping>
4、hibernate配置文件
<?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://localhost:3306/test?useUnicode=true&characterEncoding=UTF8</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">123456</property> <!-- 设置事务隔离级别 , 取值可以是 1、2、4、8 --> <property name="hibernate.connection.isolation">1</property> <!-- 设置事务是否自动提交 , 取值可以是 true 、false --> <property name="hibernate.connection.autocommit">false</property> <!-- 指定数据方言类 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 指示是否显示 执行过的 SQL 语句 --> <property name="hibernate.show_sql">true</property> <!-- 指示是否对 SQL 语句进行格式化输出 --> <property name="hibernate.format_sql">false</property> <mapping resource="ecut/self/entity/Category.hbm.xml"/> </session-factory> </hibernate-configuration>
5、测试类
第一个角度: 从 一对多角度测试
存: 保存一个分类,并为其添加子分类
取: 获取一个分类,并获取其子分类
package ecut.self.test.onetomany; import java.util.ArrayList; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; import ecut.self.entity.Category; public class TestOneToMany { private SessionFactory factory ; private Session session ; public @Before void init() { // 创建一个 Configuration 对象,用来读取配置文件 ( 默认位置、默认名称 ) Configuration config = new Configuration(); // 读取配置文件 config.configure("ecut/self/hibernate.cfg.xml"); //config.configure(); // 读取 默认位置 ( 当前 classpath ) 的 默认名称 ( hibernate.cfg.xml ) 的配置文件 // 使用 Configuration 创建 SessionFactory factory = config.buildSessionFactory(); // 创建 Session 对象 ( 这里的 Session 是 Java 程序 跟 数据库 之间的 会话 ) session = factory.openSession(); } /** 获取一个分类,并获取其子分类 */ public @Test void loadCategory(){ Category c = session.find( Category.class , 1001 ); if( c == null ){ System.out.println( "未找到分类" ); } else { System.out.println( "分类: " + c.getName()); List<Category> categories = c.getCategories(); if( categories == null || categories.isEmpty() ) { System.out.println( c.getName() + " 没有子分类" ); } else { for( int i = 0 , n =categories.size() ; i < n ; i++ ){ Category s = categories.get( i ); System.out.println( " " + s.getName() + " , " + s.getPosition() ); } } } } /** 保存一个分类,并指定其子分类 ( 子分类被一起保存 )*/ public @Test void saveCategory(){ Category c =new Category(); c.setId(3001); c.setName("动漫"); List<Category> categories = new ArrayList<Category>() ; Category c1 =new Category(); c1.setId(3002); c1.setName("火影忍者"); c1.setParent(c); categories.add(c1); Category c2 =new Category(); c2.setId(3003); c2.setName("海贼王"); c2.setParent(c); categories.add(c2); Category c3 =new Category(); c3.setId(3004); c3.setName("名侦探柯南"); c3.setParent(c); categories.add(c3); c.setCategories(categories); Transaction t=session.getTransaction(); t.begin(); session.save(c); t.commit(); } public @After void destory(){ session.close(); factory.close(); } }
若id和position在映射配置文件中配置了,但测试的时候在测试类中由setter了position和id,就会抛出如下异常:
javax.persistence.OptimisticLockException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
第二个角度: 从 多对一角度测试
存: 保存一个分类,并为其添加父分类
取: 获取一个分类,并获取其父分类
package ecut.self.test.manytoone; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; import ecut.self.entity.Category; public class TestManyToOne { private SessionFactory factory ; private Session session ; public @Before void init() { // 创建一个 Configuration 对象,用来读取配置文件 ( 默认位置、默认名称 ) Configuration config = new Configuration(); // 读取配置文件 config.configure("ecut/self/hibernate.cfg.xml"); //config.configure(); // 读取 默认位置 ( 当前 classpath ) 的 默认名称 ( hibernate.cfg.xml ) 的配置文件 // 使用 Configuration 创建 SessionFactory factory = config.buildSessionFactory(); // 创建 Session 对象 ( 这里的 Session 是 Java 程序 跟 数据库 之间的 会话 ) session = factory.openSession(); } public @Test void loadCategory(){ Category s = session.find( Category.class , 1002 ); if( s == null ){ System.out.println( "未找到分类" ); } else { System.out.println( s.getName() ); Category p = s.getParent(); if( p == null ){ System.out.println( s.getName() + "是一个顶级分类" ); } else { System.out.println( s.getName() + " 分类的 父分类是 " + p.getName() ); } } } public @Test void saveCategory(){ Category p =new Category(); p.setId(4001); p.setName("银行"); Category s =new Category(); s.setId(4002); s.setName("中国工商银行"); s.setParent(p); Transaction t=session.getTransaction(); t.begin(); session.save(s); t.commit(); } public @After void destory(){ session.close(); factory.close(); } }
第三个角度: 综合
存: 保存一个分类,指定其 父分类 和 子分类
取: 获取一个分类,并获取其 父分类 和 子分类
package ecut.self.test; import java.util.ArrayList; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; import ecut.self.entity.Category; public class TestSelf { private SessionFactory factory ; private Session session ; public @Before void init() { // 创建一个 Configuration 对象,用来读取配置文件 ( 默认位置、默认名称 ) Configuration config = new Configuration(); // 读取配置文件 config.configure("ecut/self/hibernate.cfg.xml"); //config.configure(); // 读取 默认位置 ( 当前 classpath ) 的 默认名称 ( hibernate.cfg.xml ) 的配置文件 // 使用 Configuration 创建 SessionFactory factory = config.buildSessionFactory(); // 创建 Session 对象 ( 这里的 Session 是 Java 程序 跟 数据库 之间的 会话 ) session = factory.openSession(); } public @Test void loadCategory(){ Category s = session.find( Category.class , 2002 ); if( s == null ){ System.out.println( "未找到分类" ); } else { System.out.println( s.getName() ); Category p = s.getParent(); if( p == null ){ System.out.println( s.getName() + "是一个顶级分类" ); } else { System.out.println( s.getName() + " 分类的 父分类是 " + p.getName() ); } List<Category> categories = s.getCategories(); if( categories == null || categories.isEmpty() ) { System.out.println( s.getName() + " 没有子分类" ); } else { for( int i = 0 , n =categories.size() ; i < n ; i++ ){ Category c = categories.get( i ); System.out.println( " " + c.getName() + " , " + c.getPosition() ); } } } } public @Test void saveCategory(){ Category p =new Category(); p.setId(5001); p.setName("支付"); Category s =new Category(); s.setId(5002); s.setName("网银"); s.setParent(p); List<Category> categories = new ArrayList<Category>() ; Category c1 =new Category(); c1.setId(5003); c1.setName("B2B"); c1.setParent(s); categories.add(c1); Category c2 =new Category(); c2.setId(5004); c2.setName("B2C"); c2.setParent(s); categories.add(c2); s.setCategories(categories); Transaction t=session.getTransaction(); t.begin(); session.save(s); t.commit(); } public @After void destory(){ session.close(); factory.close(); } }
转载请于明显处标明出处: