Hibernate ORM框架——综合
换一个连接数据mySql数据库的项目:HibernateStudy_cascade_inverse_query **********1.支持sql server需要的设置******************************************************* a):驱动jar的处理-->导入sqljdbc42.jar连接数据库驱动 b):修改hibernate.cfg.xml中配置相关的连接,方言 <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property> <property name="connection.url">jdbc:sqlserver://localhost:1433;databaseName=demo</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <property name="dialect">org.hibernate.dialect.SQLServer2008Dialect</property> c):开启TCP/IP的支持-->计算机管理,服务和应用程序,SQL Server配置管理器,SQL Native Cloient 10.0配置,客户端协议 d):启动sql server的服务 **********2.关联数据的处理**************************************************************** 关联数据的插入,更新(修改),删除的顺序 假定A是主表,B是子表 create table A ( aid varchar2(255 char) not null, primary key(aid) ) create table B ( bid varchar2(255 char) not null, primary key(bid), raid foreign key(aid) references A //外键 ) 在MySQL数据库层面*************************************** a)insert(添加操作) : 先主表,后从(子)表 b)update(更新)(我们一般是不更新表的主键) 在数据库层面来看,如果不考虑更新主键,顺序是无关紧要的。 c)delete(删除) 先删从表(子表)的,然后再删主表 在hibernate代码层面************************************* 关联数据如果MySQL的代码和自己预想中的有出入,如何处理,需考虑的点。 1.考虑调用session对象的save,update,delete的顺序问题 2.考虑在代码层面有没有设置关系,外键是否允许为null 3.考虑对象此时的状态 帮助判断工具:sql server的监听器 **********3.cascade(级联)************************************************************* **********4.inverse(确定关系维护方)****************************************************** 关系维护,本质就是谁负责处理外键列的值。 inserse 一般是出现的映射文件的set元素里面 因为出现在set里面,也就是出现主表的映射文件中 如果把inserse设置为true,就表示由对方,也就是 子表来维护关系(就不会继续进行修改操作,[而此时查表时的外键值也为空]),主的一方不管。 -->在添加子表的时候,相关联的主表就跟着添加了 一般默认inserse的值为false,即为自己就是维护关系方,会进行修改(更新)操作 所以一般来说永远交给子表来维护关系,是比较合理的(比如:一个应届生,他并不属于任何部门, 那么在这个应届生中存在两张表,一张是个人的信息表,一张是部门表。在个人信息表中的所属部门可以为空, 等到该应届生,正式成为某某部门的时候,才不为空。也同时说明,外键一般时可以为空的) **********5.关联数据的查询形式(检索策略)**************************************************** 关联数据的加载,有3种情况 1.延迟(lazy)也叫作懒加载: 当只在查找班级数据后,马上调用session.close();那么久默认为延迟(lazy)加载。即后面还没有查找完的语句就不查找了 默认:lazy="true" 2.勤加载(eager) 当只在查找班级数据后,马上调用session.close();而后面还没有查找完的语句就系统仍然自动查找,称为勤加载(eager) lazy="false"如在学生这边加,在查询学生信息的同时也查询班级信息是正常的 3.外键加载(显式加载): outer-join="true":查询的SQL语句中只用左外连接显示出一条查询结果 避免普通查询,两张表,则需要发送两条select语句。
补充:3.级联cascade
(1)class类映射文件
<?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="shuang.m2oo2m"> <class name="ClassInfo" table="CLASSINFO"> <id name="cid" column="cid"> <generator class="assigned"></generator> </id> <property name="name"></property> <set name="persons" cascade="all"> <key column="rci"></key> <one-to-many class="Person"/> </set> </class> </hibernate-mapping>
(2.1)Main测试,级联添加
private static void cascadeInsert() { SessionFactory sf = HibernateUtil.getSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); ClassInfo ci = new ClassInfo(); ci.setCid("c1111"); ci.setName("banji1"); Set<Person> set = new HashSet<Person>(); Person p = new Person(); p.setPid("p111"); p.setName("ren1"); //p.setCi(ci);可以不需要, set.add(p); ci.setPersons(set);//此处已经说明了它俩关联了 s.save(ci); //只把ci的数据持久化(save),不save人。并且在ClassInfo_m2oo2m.xml里写cascade="all" //班级和人的数据均正常添加 tx.commit(); s.close(); sf.close(); //运行结果为:先查询这个班级有没有人,然后再添加班级,添加人 /*create table CLASSINFO ( cid varchar(255) not null, name varchar(255), primary key (cid) ) create table persons ( pid varchar(255) not null, name varchar(255), rci varchar(255), primary key (pid) ) alter table persons add constraint FK7q2p61lu2253rtputmlhokd1e foreign key (rci) references CLASSINFO -----------------重点----------------------- select person_.pid, person_.name as name2_1_, person_.rci as rci3_1_ from persons person_ where person_.pid=? insert into CLASSINFO (name, cid) values (?, ?) insert into persons (name, rci, pid) values (?, ?, ?) update persons set rci=? where pid=?*/ //反之,如果不使用级联(在ClassInfo_m2oo2m.xml里写cascade="all") //则数据在直接添加时并不会去找是存在临时的人的数据, //但是又因为人和班级有关联,会报错 /*Hibernate: insert into CLASSINFO (name, cid) values (?, ?) Hibernate: update persons set rci=? where pid=?*/ }
(2.2)Main测试,级联删除
private static void cascadeDelete() { SessionFactory sf = HibernateUtil.getSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); ClassInfo ci = s.get(ClassInfo.class, "c1111"); s.delete(ci); /*不使用级联的普通删除结果(不在ClassInfo_m2oo2m.xml里写cascade="all"): * 先根据id查到所删除的数据,然后再修改所关联的人的班级信息为null。 * 最后删除该行 * Hibernate: select classinfo0_.cid as cid1_0_0_, classinfo0_.name as name2_0_0_ from CLASSINFO classinfo0_ where classinfo0_.cid=? Hibernate: update persons set rci=null where rci=? Hibernate: delete from CLASSINFO where cid=?*/ /*使用级联的普通删除结果(在ClassInfo_m2oo2m.xml里写cascade="all"): * 班级和所关联的人的数据都一同删掉 * Hibernate: select classinfo0_.cid as cid1_0_0_, classinfo0_.name as name2_0_0_ from CLASSINFO classinfo0_ where classinfo0_.cid=? Hibernate: select persons0_.rci as rci3_1_0_, persons0_.pid as pid1_1_0_, persons0_.pid as pid1_1_1_, persons0_.name as name2_1_1_, persons0_.rci as rci3_1_1_ from persons persons0_ where persons0_.rci=? Hibernate: update persons set rci=null where rci=? Hibernate: delete from persons where pid=? Hibernate: delete from persons where pid=? Hibernate: delete from CLASSINFO where cid=? * */ tx.commit(); s.close(); sf.close(); }
补充:4.inverse(确定关系维护方)
Main测试
private static void testInverse() { SessionFactory sf = HibernateUtil.getSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); ClassInfo ci = new ClassInfo(); ci.setCid("c1111"); ci.setName("banji1"); Set<Person> set = new HashSet<Person>(); Person p = new Person(); p.setPid("p111"); p.setName("ren1"); p.setCi(ci); set.add(p); ci.setPersons(set); p.setCi(ci); s.save(ci); s.save(p); tx.commit(); s.close(); sf.close(); }
补充:5.关联数据的查询形式(检索策略)
(5.1)班级的映射文件
<?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="shuang.m2oo2m"> <class name="ClassInfo" table="CLASSINFO"> <id name="cid" column="cid"> <generator class="assigned"></generator> </id> <property name="name"></property> <set name="persons" lazy="true"> <key column="rci"></key> <one-to-many class="Person"/> </set> </class> </hibernate-mapping>
(5.2)Main测试代码(是否为勤加载或者懒加载)
private static void LazyFlag() { SessionFactory sf = HibernateUtil.getSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); ClassInfo ci = s.get(ClassInfo.class, "c1111"); System.out.println(ci.getName()); tx.commit(); s.close(); Set<Person> persons = ci.getPersons(); for(Person p : persons){ System.out.println(p.getName()); } s.close(); sf.close(); /*不写,默认懒加载==班级的映射文件中,默认:lazy="true" * 当只在查找班级数据后,马上调用session.close();那么久默认为延迟(lazy)加载。即后面还没有查找完的语句就不查找了 * Hibernate: select classinfo0_.cid as cid1_0_0_, classinfo0_.name as name2_0_0_ from CLASSINFO classinfo0_ where classinfo0_.cid=? banji1 * */ /*反之:如果班级的映射文件中,设置关键词lazy="false":即为勤加载 * 当只在查找班级数据后,马上调用session.close();而后面还没有查找完的语句就系统仍然自动查找,称为勤加载(eager) * */ //注意:一般班级中默认是懒加载,人中默认是勤加载,是正常的 }
(5.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 package="shuang.m2oo2m"> <class name="ClassInfo" table="CLASSINFO"> <id name="cid" column="cid"> <generator class="assigned"></generator> </id> <property name="name"></property> <set name="persons" outer-join="true"> <key column="rci"></key> <one-to-many class="Person"/> </set> </class> </hibernate-mapping>
Main测试:
private static void showLoad() { SessionFactory sf = HibernateUtil.getSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); ClassInfo ci = s.get(ClassInfo.class, "c1111"); System.out.println(ci.getName()); tx.commit(); s.close(); sf.close(); /*在班级映射文件中使用关键词outer-join="true"的查询结果: * 会在查询班级的同时,把相关联表的一起查询 * Hibernate: select classinfo0_.cid as cid1_0_0_, classinfo0_.name as name2_0_0_, persons1_.rci as rci3_1_1_, persons1_.pid as pid1_1_1_, persons1_.pid as pid1_1_2_, persons1_.name as name2_1_2_, persons1_.rci as rci3_1_2_ from CLASSINFO classinfo0_ left outer join persons persons1_ on classinfo0_.cid=persons1_.rci where classinfo0_.cid=? banji1 * */ /*不使用的结果:只会查询他自己的 * Hibernate: select classinfo0_.cid as cid1_0_0_, classinfo0_.name as name2_0_0_ from CLASSINFO classinfo0_ where classinfo0_.cid=? banji1 * * */ //好处:避免普通查询,两张表,则需要发送两条select语句。 }
/*以上个人整理笔记,如果有误或者有不懂的地方,欢迎评论与指出*/