1.Hibernate关系映射总结
一、概念:
关系:名词,事物之间相互作用、相互联系的状态。
关联:名词:表示对象(数据库表)之间的关系;动词:将对象(数据库表)之间通过某种方式联系起来。
映射:将一种形式转化为另一种形式,包括关系。
级联:动词,有关系的双方中操作一方,另一方也将采取一些动作。
值类型:对象不具备数据库同一性,属于一个实体实例其持久化状态被嵌入到所拥有的实体的表行中,没有标识符。
实体类型:具有数据库标识符。
二、数据库:
1、关系
2.1.1、一对一、一对多、多对多
2.1.2、如何表示? 外键+索引
2、级联:
2.2.1、级联删除
三、面向对象语言中(Java中):
1、关系
3.1.1、一对一、一对多、多对多
3.1.2、如何表示? 实例变量(对象+集合)
2、级联:
3.2.1、级联删除
3.2.2、级联更新
3.2.3、级联保存
四、如何把数据库关系表示为面向对象中的关系:
1、关联:将数据库表之间的关系转化为对象之间的关系;在Hibernate中总指实体之间的关系。
2、映射:完成java对象到数据库表的双向转换。
3、级联(可选):将数据库中的级联转化为对象中的级联(两者(对象和数据库表)没关系)。
4、Hibernate的表和对象的映射:
1、实体类型映射:
4.1.1、主键之间的映射
4.1.2、类属性与表字段的映射
4.1.3、组件映射
4.1.4、集合映射
2、实体关联关系映射:
4.2.1、关联关系映射
五、Hibernate映射示例:
5.1、实现
5.1.1、数据库表定义(主表)
5.1.1.1、用户表
- CREATE TABLE TBL_USER (
- UUID NUMBER(10) NOT NULL,
- NAME VARCHAR2(100),
- AGE NUMBER(10) NOT NULL,
- PROVINCE VARCHAR2(100),
- CITY VARCHAR2(100),
- STREET VARCHAR2(100),
- CONSTRAINT PK_USER PRIMARY KEY(UUID));
5.1.1.2、用户普通信息表(一个用户有一个资料)
- CREATE TABLE TBL_USER_GENERAL (
- UUID NUMBER(10) NOT NULL,
- REALNAME VARCHAR2(10),
- GENDER VARCHAR2(10),
- BIRTHDAY NUMBER(10),
- HEIGHT NUMBER(10),
- WEIGHT NUMBER(10) ,
- CONSTRAINT PK_USER_GENERAL PRIMARY KEY(UUID),
- CONSTRAINT FK_USER_GENERAL FOREIGN KEY(UUID)
- REFERENCES TBL_USER(UUID));
5.1.1.3、农场表(一个用户有多个农场)
- CREATE TABLE TBL_FARM (
- UUID NUMBER(10) NOT NULL,
- NAME VARCHAR2(10),
- FK_USER_ID NUMBER(10),
- CONSTRAINT PK_FARM PRIMARY KEY(UUID),
- CONSTRAINT FK_USER_FARM FOREIGN KEY(FK_USER_ID)
- REFERENCES TBL_USER(UUID));
5.1.2、对象定义
5.1.2.1、用户地址Model
- package cn.javass.h3test.model;
- public class AddressModel implements java.io.Serializable {
- private String province;//省
- private String city;//市
- private String street;//街道
- }
5.1.2.2、用户Model
- package cn.javass.h3test.model;
- import java.util.HashSet;
- import java.util.Set;
- public class UserModel implements java.io.Serializable {
- private int uuid;
- private String name;//名称
- private int age;//年龄
- private AddressModel address;//地址
- private UserGeneralModel userGeneral;//用户普通信息
- private Set<FarmModel> farms = new HashSet<FarmModel>();//拥有的农场
- }
5.1.2.3、用户普通信息Model
- package cn.javass.h3test.model;
- public class UserGeneralModel implements java.io.Serializable {
- private int uuid;
- private String realname;//真实姓名
- private String gender;//性别
- private String birthday;//生日
- private int weight;//体重
- private int height;//身高
- private UserModel user;//所属用户
- }
5.1.2.4、农场Model
- package cn.javass.h3test.model;
- public class FarmModel implements java.io.Serializable {
- private int uuid;
- private String name;//农场的名称
- private UserModel user;//所属用户
- }
5.2、配置
5.2.1、实体类型映射:
5.2.1.1、主键的映射(UserModel.hbm.xml)
- <id name="uuid">
- <generator class="sequence">
- <param name="sequence">user_uuid</param>
- </generator>
- </id>
5.2.1.2、类属性与表字段的映射(UserModel.hbm.xml)
5.2.1.3、组件映射(UserModel.hbm.xml)
- <component name="address" class="cn.javass.h3test.model.AddressModel">
- <property name="province"/>
- <property name="city"/>
- <property name="street"/>
- </component>
5.2.1.4、集合映射(Set、List、Map) (都是通过外键连接的,,,默认延迟抓取)
Set:
- <set name="farmSet" table="TBL_FARM" >
- <key column="fk_user_id"/><!—该外键是tbl_farm的-->
- <element type="string" column="name"/>
- </set>
- <list name="farmList" table="TBL_FARM">
- <key column="fk_user_id"/>
- <list-index column="uuid"></list-index>
- <element type="string" column="name"/>
- </list>
- <map name="farmMap" table="TBL_FARM">
- <key column="fk_user_id"/>
- <map-key type="int" column="uuid"/>
- <element type="string" column="name"></element>
- </map>
对于集合类型默认是延迟加载的,且只能单向导航,不能双向。
5.2.2、实体关联关系映射:
5.2.2.1、单向关联关系映射,不演示。
5.2.2.2、双向关联关系映射
- 单向
- 定义:不知道另一端什么情况,获取一端另一端自动获取,因为单向,你不知道另一侧是什么。
- 如 class A{ B b;}
- class B{ }
- 只能从A导航到B,不能从B导航到A
- 关系维护:另一端维护,如B维护
- 双向
- 定义:知道另一端(两个单向),从一端获取另一端,从另一端也能获取一端
- 如 class A{ B b;}
- class B{ A a;}
- 只能从A导航到B,也能从B导航到A
- 关系维护:两端,对关联的一侧所作的改变,会立即影响到另一侧
- 关联的多样性:
- 从一侧看是多对一,从另一侧看是一对多
- 另外还有一对一、多对多
- EJB CMP:天生双向,对关联的一侧所作的改变,会立即影响到另一侧,
- 如userGeneral.set(user),则自动调用user.setUserGeneral(userGeneral)
- Hibernate、JPA:天生单向,两侧关系的维护是不同的关联,必须手工维护
- 如userGeneral.set(user),则需要手工调用user.setUserGeneral(userGeneral)。
5.2.2.3、一对一主键关系映射(非延迟抓取)
配置1(UserModel.hbm.xml)
配置2(UserGeneralModel.hbm.xml)
- <id name="uuid">
- <generator class="foreign">
- <param name="property">user</param>
- </generator>
- </id>
- <one-to-one name="user"
- class="cn.javass.h3test.model.UserModel"/>
关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。
测试:保存对象,只需保存user,自动级联保存用户信息Model
- UserModel user = new UserModel();
- user.setName("昵称");
- UserGeneralModel userGeneral = new UserGeneralModel();
- userGeneral.setRealname("真实姓名");
- userGeneral.setUser(user);
- user.setUserGeneral(userGeneral);
- session.save(user);
- //若没有cascade="all",这句必须
- //session.save(userGeneral);
1、一对一必须手工维护双向关系。
2、cascade="all":表示保存user时自动保存userGeneral,否则还需要一条save(userGeneral)
3、constrained:添加把userGeneral表的主键映射到user主键的外键约束
5.2.2.4、一对多关系映射(父/子关系映射)
配置1(UserModel.hbm.xml)
- <set name="farms" cascade="all">
- <key column="fk_user_id"/>
- <one-to-many class="cn.javass.h3test.model.FarmModel"/>
- </set>
配置2(FarmModel.hbm.xml)
测试:保存对象,只需保存user,自动级联保存用户信息Model
- UserModel user = new UserModel();
- user.setName("昵称");
- UserGeneralModel userGeneral = new UserGeneralModel();
- userGeneral.setRealname("真实姓名");
- userGeneral.setUser(user);
- user.setUserGeneral(userGeneral);
- FarmModel farm = new FarmModel();
- farm.setName("farm1");
- farm.setUser(user);
- user.getFarms().add(farm);
- //session.save(farm);//若没有cascade=all的话需要这条语句
- session.save(user);
以上配置有问题:
- insert into TBL_USER (name, age, province, city, street, uuid) values (?, ?, ?, ?, ?, ?)
- insert into TBL_USER_GENERAL (realname, gender, birthday, weight, height, uuid) values (?, ?, ?, ?, ?, ?)
- insert into TBL_FARM (name, fk_user_id, uuid) values (?, ?, ?)
- update TBL_FARM set fk_user_id=? where uuid=?
1、持久化user(UserModel);
2、持久化user的一对一关系,即userGeneral(UserGeneralModel);
3、持久化user的一对多关系,即farms(Set<FarmModel>);
3.1、首先发现farm是TO,级联save;(因为在这可能是PO,PO的话就应该update,而不是save);
3.2、其次发现farm在farms集合中,因此需要更新外键(fk_user_id),即执行“update TBL_FARM set fk_user_id=? where uuid=? “。
解决这个问题:
告诉Hibernate应该只有一端来维护关系(外键),另一端不维护;通过指定<set>端的inverse=”true”,表示关系应该由farm端维护。即更新外键(fk_user_id)将由farm端维护。
配置修改(UserModel.hbm.xml)
- <set name="farms" cascade="all" inverse="true">
- <key column="fk_user_id"/>
- <one-to-many class="cn.javass.h3test.model.FarmModel"/>
- </set>
再测试:保存对象,只需保存user,自动级联保存用户信息Model
- UserModel user = new UserModel();
- user.setName("昵称");
- UserGeneralModel userGeneral = new UserGeneralModel();
- userGeneral.setRealname("真实姓名");
- userGeneral.setUser(user);
- user.setUserGeneral(userGeneral);
- FarmModel farm = new FarmModel();
- farm.setName("farm1");
- farm.setUser(user);
- user.getFarms().add(farm);
- //session.save(farm);//若没有cascade=all的话需要这条语句
- session.save(user);
更新外键,需要修改FarmModel的外键并update:
- insert into TBL_USER (name, age, province, city, street, uuid) values (?, ?, ?, ?, ?, ?)
- insert into TBL_USER_GENERAL (realname, gender, birthday, weight, height, uuid) values (?, ?, ?, ?, ?, ?)
- insert into TBL_FARM (name, fk_user_id, uuid) values (?, ?, ?)
级联删除
1、当删除user时自动删除user下的farm
结果:
- Hibernate: delete from TBL_USER_GENERAL where uuid=?
- Hibernate: delete from TBL_FARM where uuid=?
- Hibernate: delete from TBL_USER where uuid=?
2、删除user中的farms的一个元素
- UserModel user =
- (UserModel) session.get(UserModel.class, 118);
- FarmModel farm = (FarmModel) user.getFarms().toArray()[user.getFarms().size() - 1];
- user.getFarms().remove(farm);//1.必须先从集合删除
- session.delete(farm);//2.然后才能删除
结果:
如果将子对象从集合中移除,实际上我们是想删除它。要实现这种要求,就必须使用cascade="all-delete-orphan"
。无需再调用session.delete(farm)
5.2.2.5、多对多关系映射:不用
为什么不使用多对多:当添加新字段时给谁?
那实际项目如何用:拆成两个一对多。
六、涉及的SQL语句会按照下面的顺序发出执行:
1、查询
1、所有对实体进行插入的语句,其顺序按照对象执行Session.save()的时间顺序
2、所有对实体进行更新的语句
3、所有进行集合插入的语句 (实体类型)
4、所有对集合元素进行删除、更新或插入的语句 (值类型)
5、所有进行集合删除的语句 (实体类型)
6、所有对实体进行删除的语句,其顺序按照对象执行Session.delete()的时间顺序
(有一个例外是,如果对象使用native方式来生成ID(持久化标识)的话,它们一执行save就会被插入。)
七、影响关系映射抓取的cfg配置:
hibernate.max_fetch_depth | 为单向关联(一对一, 多对一)的外连接抓取(outer join fetch)树设置最大深度. 值为0意味着将关闭默认的外连接抓取. 取值 建议在0到3之间取值 |
hibernate.default_batch_fetch_size | 为Hibernate关联的批量抓取设置默认数量. 取值 建议的取值为4, 8, 和16 |
如果你的数据库支持ANSI, Oracle或Sybase风格的外连接, 外连接抓取通常能通过限制往返数据库次数 (更多的工作交由数据库自己来完成)来提高效率. 外连接抓取允许在单个SELECTSQL语句中, 通过many-to-one, one-to-many, many-to-many和one-to-one关联获取连接对象的整个对象图.
将hibernate.max_fetch_depth设为0能在全局 范围内禁止外连接抓取. 设为1或更高值能启用one-to-one和many-to-one外连接关联的外连接抓取, 它们通过 fetch="join"来映射.
八、抓取策略
1、抓取策略定义
抓取策略(fetching strategy) 是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL 或条件查询(CriteriaQuery)
中重载声明。
2、Hibernate3 定义了如下几种抓取策略:
连接抓取(Join fetching) - Hibernate通过 在SELECT
语句使用OUTER JOIN
(外连接)来 获得对象的关联实例或者关联集合。 默认非延迟加载
集合抓取需要通过配置fetch="join"来指定。下行数据太多(冗余),IO
- //配置 fetch="join"( lazy="true"不起作用了)
- session.get(UserModel.class, 118);//是获取对象的
- Hibernate: select … from TBL_USER usermodel0_, TBL_FARM farms1_
- where usermodel0_.uuid=farms1_.fk_user_id(+) and usermodel0_.uuid=?
查询抓取(Select fetching) - 另外发送一条 SELECT
语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false"
禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
- 配置 lazy=”true”默认(或者lazy="false" fetch="select")
- session.get(UserModel.class, 118);//是获取对象的
- Hibernate: select … from TBL_USER usermodel0_ where usermodel0_.uuid=?
- Hibernate: select … from TBL_FARM farms0_ where farms0_.fk_user_id=?
默认用于lazy="true"情况的集合抓取,如果lazy="false",
需要指定fetch="select"来通过查询抓取。会造成DB的CPU利用率非常高,计算密集
子查询抓取(Subselect fetching) - 另外发送一条SELECT
语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定lazy="false"
禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
当通过Query等接口查询多个实体时,如果指定fetch="subselect"则将通过子查询获取集合
- 配置fetch="subselect"
- Query q = session.createQuery("from UserModel");
- System.out.println(q.list());
- Hibernate: select …… from TBL_USER usermodel0_
- Hibernate: select …… from TBL_FARM farms0_ where farms0_.fk_user_id
- in (select usermodel0_.uuid from TBL_USER usermodel0_)
批量抓取(Batch fetching) - 对查询抓取的优化方案, 通过指定一个主键或外键列表,Hibernate使用单条SELECT
语句获取一批对象实例或集合。
当通过Query等接口查询多个实体时,如果指定farm的batch-size="……"则将通过使用单条SELECT
语句获取一批对象实例或集合。
- Query q = session.createQuery("from UserModel");
- List<UserModel> userList = q.list(); System.out.println(userList);
- Hibernate: select … TBL_USER usermodel0_
- Hibernate: select … from TBL_FARM farms0_ where farms0_.fk_user_id in (?, ?)
可指定全局批量抓取策略: hibernate.default_batch_fetch_size,取值:建议的取值为4, 8, 和16。
如果batch-size="4",而某个user有19个农场,Hibernate将只需要执行五次查询,分别为4、4、4、4、3。
测试必须数据量足够多,,如果只有一条不行
3、使用延迟属性抓取(Using lazy property fetching)
属性的延迟载入要求在其代码构建时加入二进制指示指令(bytecode instrumentation),如果你的持久类代码中未含有这些指令, Hibernate将会忽略这些属性的延迟设置,仍然将其直接载入。
Hibernate3对单独的属性支持延迟抓取,这项优化技术也被称为组抓取(fetch groups)。 请注意,该技术更多的属于市场特性。在实际应用中,优化行读取比优化列读取更重要。但是,仅载入类的部分属性在某些特定情况下会有用,例如在原有表中拥有几百列数据、数据模型无法改动的情况下。
4、Hibernate在抓取时会lazy区分下列各种情况:
立即抓取 - 当宿主被加载时,关联、集合或属性被立即抓取。
Lazy collection fetching,延迟集合抓取- 直到应用程序对集合进行了一次操作时,集合才被抓取。(对集合而言这是默认行为。)
Extra-lazy" collection fetching,"Extra-lazy"集合抓取 -对集合类中的每个元素而言,都是直到需要时才去访问数据库。除非绝对必要,Hibernate不会试图去把整个集合都抓取到内存里来(适用于非常大的集合)。
- // lazy="extra"
- Query q = session.createQuery("from UserModel");
- Iterator it = q.iterate(); System.out.println(((UserModel)it.next()).getFarms().size());
- //或
- List<UserModel> userList = q.list(); System.out.println(userList.get(0).getFarms().size());
- Hibernate: select usermodel0_.uuid as col_0_0_ from TBL_USER usermodel0_
- Hibernate: select … from TBL_USER usermodel0_ where usermodel0_.uuid=?
- Hibernate: select count(uuid) from TBL_FARM where fk_user_id =?
- //或
- Hibernate: select … from TBL_USER usermodel0_
- Hibernate: select count(uuid) from TBL_FARM where fk_user_id =?
对于调用size()、contains、isEmpty是一种优化,不读取所有级联,而是按条件生产不同的sql。
Proxy fetching,代理抓取 - 对返回单值的关联而言,当其某个方法被调用,而非对其关键字进行get操作时才抓取。
- //默认 <many-to-one name="user" ……lazy="false"/>
- FarmModel farm = (FarmModel) session.get(FarmModel.class, 121);
- System.out.println(farm.getUser().getUuid());
- Hibernate: select … from TBL_FARM farmmodel0_ where farmmodel0_.uuid=?
- Hibernate: select … from TBL_USER usermodel0_ where usermodel0_.uuid=?
- 118
- // <many-to-one name="user" ……lazy="proxy"/>
- FarmModel farm = (FarmModel) session.get(FarmModel.class, 121);
- System.out.println(farm.getUser().getUuid());
- Hibernate: select … from TBL_FARM farmmodel0_ where farmmodel0_.uuid=?
- 118
注:如果constrained="false"或基于主键的一对一
, 不可能使用代理,Hibernate会采取预先抓取!
"No-proxy" fetching,非代理抓取 - 对返回单值的关联而言,当实例变量被访问的时候进行抓取。与上面的代理抓取相比,这种方法没有那么“延迟”得厉害(就算只访问标识符,也会导致关联抓取)但是更加透明,因为对应用程序来说,不再看到proxy。这种方法需要在编译期间进行字节码增强操作,因此很少需要用到。
Lazy attribute fetching,属性延迟加载 - 对属性或返回单值的关联而言,当其实例变量被访问的时候进行抓取。需要编译期字节码强化,因此这一方法很少是必要的。
这里有两个正交的概念:关联何时被抓取,以及被如何抓取(会采用什么样的SQL语句)。不要混淆它们!我们使用抓取
来改善性能。我们使用延迟
来定义一些契约,对某特定类的某个脱管的实例,知道有哪些数据是可以使用的。
九、抓取优化
1、集合N+1:
可以使用batch-size来减少获取次数,即如batch-size=”10”,则是N/10+1。
开启二级缓存。
对于集合比较小且一定会用到的可采用fetch=”join”,这样只需一条语句。
2、笛卡尔积问题:
- <set name="farms" cascade="all,all-delete-orphan" inverse="true" fetch="join">
- <key column="fk_user_id"/>
- <one-to-many class="cn.javass.h3test.model.FarmModel"/>
- </set>
- <set name="hourses" cascade="all,all-delete-orphan" inverse="true" fetch="join">
- <key column="fk_user_id"/>
- <one-to-many class="cn.javass.h3test.model.HourseModel"/>
- </set>
如上配置产生笛卡尔积问题。
select user.*,farm.*,hourse.* from UserModel user, FarmModel farm, HourseModel hourse
where user.uuid=farm.fk_user.uuid(+) and
user.uuid=hourse.fk_user.uuid(+)
解决方案:
1、fetch=”subselect”,子查询,每个User查询一套笛卡尔积
2、完全不采用关系映射。
3、大集合采用批处理,按块获取集合数据
4、复杂SQL太复杂太慢:找DBA优化,索引等是否有效,是否加载了过多的无用数据,拆分SQL,按需获取数据。
5、按需获取1对多中的集合。
6、缓存
2.Hibernate二级缓存
<cache usage="read-only"/>
usage有是四个属性:
transactional:必须在受管的环境下使用,保存可重复读的事务隔离级别,对于读/写比例大,很少更新的数据通常采用这种方式。
read-write:使用timestamp机制维护已提交事务隔离级别,对于读/写比例大,很少更新的数据通常采用这种方式。
nonstrict-read-writer:二级缓存与数据库中的数据可能会出现不一致的情况。在使用这种策略的时候,应该设置足够短的缓存过期时间。否则就有可能从缓存中
读到脏数据。当一些数据很少改变(一天,二天都不会改变),并且这些数据如果出现数据库与缓存的不一致的情况下影响并不大的时候,可以使用这种缓存策略。
read-only:当确定数据不会改变的时候,可以使用这种缓存策略。
- package entity;
- import java.util.HashSet;
- import java.util.Set;
- public class Team
- {
- private String id;
- private String teamName;
- @SuppressWarnings("unchecked")
- private Set students = new HashSet();
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getTeamName()
- {
- return teamName;
- }
- public void setTeamName(String teamName)
- {
- this.teamName = teamName;
- }
- @SuppressWarnings("unchecked")
- public Set getStudents()
- {
- return students;
- }
- @SuppressWarnings("unchecked")
- public void setStudents(Set students)
- {
- this.students = students;
- }
- }
- package entity;
- public class Student
- {
- private String id;
- private String cardId;
- private int age;
- private String name;
- private Team team;
- public Team getTeam() {
- return team;
- }
- public void setTeam(Team team) {
- this.team = team;
- }
- public Student()
- {
- }
- public Student(String id,String name, int age)
- { this.id = id;
- this.age = age;
- this.name = name;
- }
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public String getCardId()
- {
- return cardId;
- }
- public void setCardId(String cardId)
- {
- this.cardId = cardId;
- }
- public int getAge()
- {
- return age;
- }
- public void setAge(int age)
- {
- this.age = age;
- }
- }
- <?xml version='1.0' encoding='UTF-8'?>
- <!DOCTYPE hibernate-configuration PUBLIC
- "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
- <hibernate-configuration>
- <session-factory>
- <property name="connection.url">jdbc:mysql://localhost:3306/myhibernate2</property>
- <property name="connection.username">root</property>
- <property name="connection.password">baother520</property>
- <property name="format_sql">true</property>
- <property name="connection.driver_class">
- com.mysql.jdbc.Driver
- </property>
- <property name="dialect">
- org.hibernate.dialect.MySQL5Dialect
- </property>
- <property name="hibernate.connection.isolation">2</property>
- <property name="show_sql">true</property>
- <property name="hibernate.cache.use_second_level_cache">true</property>
- <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
- <mapping resource="Student.hbm.xml" />
- <mapping resource="Team.hbm.xml"/>
- </session-factory>
- </hibernate-configuration>
- <?xml version = "1.0" encoding = "UTF-8"?>
- <ehcache>
- <diskStore path = "c:/ehcache"></diskStore>
- <!-- 针对所有的实体 -->
- <defaultCache maxElementsInMemory="200" eternal = "false" timeToIdleSeconds = "50" timeToLiveSeconds="60" overflowToDisk = "true"></defaultCache>
- <!-- 针对特定的实体 -->
- <cache name = "entity.Student" maxElementsInMemory="200" eternal = "false" timeToIdleSeconds = "50" timeToLiveSeconds="60" overflowToDisk = "true"></cache>
- </ehcache>
/*
*/
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="entity.Team" table="team">
- <cache usage="read-only"/>
- <id name="id" column="id" type="string">
- <generator class="uuid"></generator>
- </id>
- <property name="teamName" column="teamName" type="string"></property>
- <set name="students" inverse="true" lazy="false" cascade="all">
- <cache usage="read-write"/>
- <key column="team_id"></key>
- <one-to-many class="entity.Student"/>
- </set>
- </class>
- </hibernate-mapping>
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="entity.Student" table="student">
- <cache usage="read-write"/>
- <id name="id" column="id" type="string">
- <generator class="uuid"></generator>
- </id>
- <property name="name" column="name" type="string"></property>
- <property name="cardId" column="cardId" type="string"></property>
- <property name="age" column="age" type="int"></property>
- <many-to-one name="team" column="team_id" class="entity.Team" cascade="save-update"></many-to-one>
- </class>
- </hibernate-mapping>
- package entity;
- import java.util.List;
- import org.hibernate.Query;
- import org.hibernate.Session;
- import org.hibernate.Transaction;
- public class HibernateTest {
- public static void main(String[] args) {
- test3();
- }
- public static void test () {
- Session session = HibernateUtil.getSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- Team team = new Team ();
- team.setTeamName("zhanglei");
- for (int i = 1;i <= 1200;i++) {
- Student student = new Student ();
- student.setAge(10+i);
- student.setCardId(""+i);
- student.setName("student"+i);
- student.setTeam(team);
- team.getStudents().add(student);
- session.save(student);
- }
- tx.commit();
- }catch(Exception ex) {
- ex.printStackTrace();
- if (null != tx) {
- tx.rollback();
- }
- }finally {
- session.close();
- }
- }
- public static void test2 () {
- Session session = HibernateUtil.getSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- Team team = (Team)session.get(Team.class, "8a68adf03eff96c0013eff96c1ea0002");
- System.out.println("the size of records are "+team.getStudents().size());
- tx.commit();
- Session session2 = HibernateUtil.getSession();
- Transaction tx2 = session2.beginTransaction();
- Student student1 = (Student)session2.get(Student.class, "8a68adf03eff96c0013eff96c1ea0001");
- System.out.println(student1.getId());
- tx2.commit();
- Session session3 = HibernateUtil.getSession();
- Transaction tx3 = session3.beginTransaction();
- Team team2 = (Team)session3.get(Team.class, "8a68adf03eff96c0013eff96c1ea0002");
- System.out.println(team2.getTeamName());
- System.out.println(team2.getStudents().size());
- tx3.commit();
- }catch(Exception ex) {
- ex.printStackTrace();
- if (null != tx) {
- tx.rollback();
- }
- }finally {
- session.close();
- }
- }
- public static void test3 () {
- Session session = HibernateUtil.getSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- Query query = session.createQuery("select new Student (s.id,s.name,s.age) from Student s");
- List list = query.list();
- System.out.println("一共有"+list.size()+"记录");
- tx.commit();
- Session session2 = HibernateUtil.getSession();
- Transaction tx2 = session2.beginTransaction();
- Student student1 = (Student)session2.get(Student.class, "8a68adf03eff96c0013eff96c1ea0001");
- System.out.println(student1.getId());
- tx2.commit();
- Session session3 = HibernateUtil.getSession();
- Transaction tx3 = session3.beginTransaction();
- Student student2 = (Student)session3.get(Student.class, "8a68adf03eff96c0013eff96c1ea0001");
- System.out.println(student2.getId());
- tx3.commit();
- }catch(Exception ex) {
- ex.printStackTrace();
- if (null != tx) {
- tx.rollback();
- }
- }finally {
- session.close();
- }
- }
- }
update:
1. 关于hibernate缓存的问题:
1.1.1. 基本的缓存原理
Hibernate缓存分为二级,第一级存放于session中称为一级缓存,默认带有且不能卸载。
第二级是由sessionFactory控制的进程级缓存。是全局共享的缓存,凡是会调用二级缓存的查询方法 都会从中受益。只有经正确的配置后二级缓存才会发挥作用。同时在进行条件查询时必须使用相应的方法才能从缓存中获取数据。比如Query.iterate()方法、load、get方法等。必须注意的是session.find方法永远是从数据库中获取数据,不会从二级缓存中获取数据,即便其中有其所需要的数据也是如此。
查询时使用缓存的实现过程为:首先查询一级缓存中是否具有需要的数据,如果没有,查询二级缓存,如果二级缓存中也没有,此时再执行查询数据库的工作。要注意的是:此3种方式的查询速度是依次降低的。
1.2. 存在的问题
1.2.1. 一级缓存的问题以及使用二级缓存的原因
因为Session的生命期往往很短,存在于Session内部的第一级最快缓存的生命期当然也很短,所以第一级缓存的命中率是很低的。其对系统性能的改善也是很有限的。当然,这个Session内部缓存的主要作用是保持Session内部数据状态同步。并非是hibernate为了大幅提高系统性能所提供的。
为了提高使用hibernate的性能,除了常规的一些需要注意的方法比如:
使用延迟加载、迫切外连接、查询过滤等以外,还需要配置hibernate的二级缓存。其对系统整体性能的改善往往具有立竿见影的效果!
(经过自己以前作项目的经验,一般会有3~4倍的性能提高)
1.2.2. N+1次查询的问题
执行条件查询时,iterate()方法具有著名的 “n+1”次查询的问题,也就是说在第一次查询时iterate方法会执行满足条件的查询结果数再加一次(n+1)的查询。但是此问题只存在于第一次查询时,在后面执行相同查询时性能会得到极大的改善。此方法适合于查询数据量较大的业务数据。
但是注意:当数据量特别大时(比如流水线数据等)需要针对此持久化对象配置其具体的缓存策略,比如设置其存在于缓存中的最大记录数、缓存存在的时间等参数,以避免系统将大量的数据同时装载入内存中引起内存资源的迅速耗尽,反而降低系统的性能!!!
1.3. 使用hibernate二级缓存的其他注意事项:
1.3.1. 关于数据的有效性
另外,hibernate会自行维护二级缓存中的数据,以保证缓存中的数据和数据库中的真实数据的一致性!无论何时,当你调用save()、update()或 saveOrUpdate()方法传递一个对象时,或使用load()、 get()、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。 当随后flush()方法被调用时,对象的状态会和数据库取得同步。
也就是说删除、更新、增加数据的时候,同时更新缓存。当然这也包括二级缓存!
只要是调用hibernate API执行数据库相关的工作。hibernate都会为你自动保证 缓存数据的有效性!!
但是,如果你使用了JDBC绕过hibernate直接执行对数据库的操作。此时,Hibernate不会/也不可能自行感知到数据库被进行的变化改动,也就不能再保证缓存中数据的有效性!!
这也是所有的ORM产品共同具有的问题。幸运的是,Hibernate为我们暴露了Cache的清除方法,这给我们提供了一个手动保证数据有效性的机会!!
一级缓存,二级缓存都有相应的清除方法。
其中二级缓存提供的清除方法为:
按对象class清空缓存
按对象class和对象的主键id清空缓存
清空对象的集合中的缓存数据等。
1.3.2. 适合使用的情况
并非所有的情况都适合于使用二级缓存,需要根据具体情况来决定。同时可以针对某一个持久化对象配置其具体的缓存策略。
适合于使用二级缓存的情况:
1、数据不会被第三方修改;
一般情况下,会被hibernate以外修改的数据最好不要配置二级缓存,以免引起不一致的数据。但是如果此数据因为性能的原因需要被缓存,同时又有可能被第3方比如SQL修改,也可以为其配置二级缓存。只是此时需要在sql执行修改后手动调用cache的清除方法。以保证数据的一致性
2、数据大小在可接收范围之内;
如果数据表数据量特别巨大,此时不适合于二级缓存。原因是缓存的数据量过大可能会引起内存资源紧张,反而降低性能。
如果数据表数据量特别巨大,但是经常使用的往往只是较新的那部分数据。此时,也可为其配置二级缓存。但是必须单独配置其持久化类的缓存策略,比如最大缓存数、缓存过期时间等,将这些参数降低至一个合理的范围(太高会引起内存资源紧张,太低了缓存的意义不大)。
3、数据更新频率低;
对于数据更新频率过高的数据,频繁同步缓存中数据的代价可能和 查询缓存中的数据从中获得的好处相当,坏处益处相抵消。此时缓存的意义也不大。
4、非关键数据(不是财务数据等)
财务数据等是非常重要的数据,绝对不允许出现或使用无效的数据,所以此时为了安全起见最好不要使用二级缓存。
因为此时 “正确性”的重要性远远大于 “高性能”的重要性。
2. 目前系统中使用hibernate缓存的建议
1.4. 目前情况
一般系统中有三种情况会绕开hibernate执行数据库操作:
1、多个应用系统同时访问一个数据库
此种情况使用hibernate二级缓存会不可避免的造成数据不一致的问题,
此时要进行详细的设计。比如在设计上避免对同一数据表的同时的写入操作,
使用数据库各种级别的锁定机制等。
2、动态表相关
所谓“动态表”是指在系统运行时根据用户的操作系统自动建立的数据表。
比如“自定义表单”等属于用户自定义扩展开发性质的功能模块,因为此时数据表是运行时建立的,所以不能进行hibernate的映射。因此对它的操作只能是绕开hibernate的直接数据库JDBC操作。
如果此时动态表中的数据没有设计缓存,就不存在数据不一致的问题。
如果此时自行设计了缓存机制,则调用自己的缓存同步方法即可。
3、使用sql对hibernate持久化对象表进行批量删除时
此时执行批量删除后,缓存中会存在已被删除的数据。
分析:
当执行了第3条(sql批量删除)后,后续的查询只可能是以下三种方式:
a. session.find()方法:
根据前面的总结,find方法不会查询二级缓存的数据,而是直接查询数据库。
所以不存在数据有效性的问题。
b. 调用iterate方法执行条件查询时:
根据iterate查询方法的执行方式,其每次都会到数据库中查询满足条件的id值,然后再根据此id到缓存中获取数据,当缓存中没有此id的数据才会执行数据库查询;
如果此记录已被sql直接删除,则iterate在执行id查询时不会将此id查询出来。所以,即便缓存中有此条记录也不会被客户获得,也就不存在不一致的情况。(此情况经过测试验证)
c. 用get或load方法按id执行查询:
客观上此时会查询得到已过期的数据。但是又因为系统中执行sql批量删除一般是
针对中间关联数据表,对于
中间关联表的查询一般都是采用条件查询 ,按id来查询某一条关联关系的几率很低,所以此问题也不存在!
如果某个值对象确实需要按id查询一条关联关系,同时又因为数据量大使用 了sql执行批量删除。当满足此两个条件时,为了保证按id 的查询得到正确的结果,可以使用手动清楚二级缓存中此对象的数据的方法!!
(此种情况出现的可能性较小)
1.5. 建议
1、建议不要使用sql直接执行数据持久化对象的数据的更新,但是可以执行 批量删除。(系统中需要批量更新的地方也较少)
2、如果必须使用sql执行数据的更新,必须清空此对象的缓存数据。调用
SessionFactory.evict(class)
SessionFactory.evict(class,id)
等方法。
3、在批量删除数据量不大的时候可以直接采用hibernate的批量删除,这样就不存在绕开hibernate执行sql产生的缓存数据一致性的问题。
4、不推荐采用hibernate的批量删除方法来删除大批量的记录数据。
原因是hibernate的批量删除会执行1条查询语句外加 满足条件的n条删除语句。而不是一次执行一条条件删除语句!!
当待删除的数据很多时会有很大的性能瓶颈!!!如果批量删除数据量较大,比如超过50条,可以采用JDBC直接删除。这样作的好处是只执行一条sql删除语句,性能会有很大的改善。同时,缓存数据同步的问题,可以采用 hibernate清除二级缓存中的相关数据的方法。
调用 SessionFactory.evict(class) ;SessionFactory.evict(class,id)等方法。
所以说,对于一般的应用系统开发而言(不涉及到集群,分布式数据同步问题等),因为只在中间关联表执行批量删除时调用了sql执行,同时中间关联表一般是执行条件查询不太可能执行按id查询。所以,此时可以直接执行sql删除,甚至不需要调用缓存的清除方法。这样做不会导致以后配置了二级缓存引起数据有效性的问题。
退一步说,即使以后真的调用了按id查询中间表对象的方法,也可以通过调用清除缓存的方法来解决。
4、具体的配置方法
根据我了解的很多hibernate的使用者在调用其相应方法时都迷信的相信“hibernate会自行为我们处理性能的问题”,或者“hibernate会自动为我们的所有操作调用缓存”,实际的情况是hibernate虽然为我们提供了很好的缓存机制和扩展缓存框架的支持,但是必须经过正确的调用其才有可能发挥作用!!所以造成很多使用hibernate的系统的性能问题,实际上并不是hibernate不行或者不好,而是因为使用者没有正确的了解其使用方法造成的。相反,如果配置得当hibernate的性能表现会让你有相当“惊喜的”发现。下面我讲解具体的配置方法.
ibernate提供了二级缓存的接口:
net.sf.hibernate.cache.Provider,
同时提供了一个默认的 实现net.sf.hibernate.cache.HashtableCacheProvider,
也可以配置 其他的实现 比如ehcache,jbosscache等。
具体的配置位置位于hibernate.cfg.xml文件中
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.provider_class">net.sf.hibernate.cache.HashtableCacheProvider</property>
很多的hibernate使用者在 配置到 这一步 就以为 完事了,
注意:其实光这样配,根本 就没有使用hibernate的二级缓存。同时因为他们在使用hibernate时大多时候是马上关闭session,所以,一级缓存也没有起到任何作用。结果就是没有使用任何缓存,所有的hibernate操作都是直接操作的数据库!!性能可以想见。
正确的办法是除了以上的配置外还应该配置每一个vo对象的具体缓存策略,在影射文件中配置。例如:
<hibernate-mapping>
<class name="com.sobey.sbm.model.entitySystem.vo.DataTypeVO" table="dcm_datatype">
<cache usage="read-write"/>
<id name="id" column="TYPEID" type="java.lang.Long">
<generator class="sequence"/>
</id>
<property name="name" column="NAME" type="java.lang.String"/>
<property name="dbType" column="DBTYPE" type="java.lang.String"/>
</class>
</hibernate-mapping>
关键就是这个<cache usage="read-write"/>,其有几个选择
read-only,read-write,transactional,等
然后在执行查询时 注意了 ,如果是条件查询,或者返回所有结果的查询,此时session.find()方法 不会获取缓存中的数据。只有调用query.iterate()方法时才会调缓存的数据。
同时 get 和 load方法 是都会查询缓存中的数据 .
对于不同的缓存框架具体的配置方法会有不同,但是大体是以上的配置
3.HIbernate之HQL查询
- package entity;
- import java.util.HashSet;
- import java.util.Set;
- public class Team
- {
- private String id;
- private String teamName;
- @SuppressWarnings("unchecked")
- private Set students = new HashSet();
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getTeamName()
- {
- return teamName;
- }
- public void setTeamName(String teamName)
- {
- this.teamName = teamName;
- }
- @SuppressWarnings("unchecked")
- public Set getStudents()
- {
- return students;
- }
- @SuppressWarnings("unchecked")
- public void setStudents(Set students)
- {
- this.students = students;
- }
- }
- <pre name="code" class="java">package entity;
- import java.util.HashSet;
- import java.util.Set;
- public class Student
- {
- private String id;
- private String cardId;
- private int age;
- private String name;
- private Set<Course> courses = new HashSet<Course>();
- public Student()
- {
- }
- public Student(String name, int age)
- {
- this.age = age;
- this.name = name;
- }
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public Set<Course> getCourses()
- {
- return courses;
- }
- public void setCourses(Set<Course> courses)
- {
- this.courses = courses;
- }
- public String getCardId()
- {
- return cardId;
- }
- public void setCardId(String cardId)
- {
- this.cardId = cardId;
- }
- public int getAge()
- {
- return age;
- }
- public void setAge(int age)
- {
- this.age = age;
- }
- }
- </pre><br>
- <br>
- <pre></pre>
- <p></p>
- <pre name="code" class="java">package entity;
- import java.util.HashSet;
- import java.util.Set;
- public class Course
- {
- private String id;
- private String name;
- private Set<Student> students = new HashSet<Student>();
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public Set<Student> getStudents()
- {
- return students;
- }
- public void setStudents(Set<Student> students)
- {
- this.students = students;
- }
- }
- </pre><br>
- <pre name="code" class="java"><?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="entity.Team" table="team">
- <id name="id" column="id" type="string">
- <generator class="uuid"></generator>
- </id>
- <property name="teamName" column="teamName" type="string"></property>
- <set name="students" inverse="true" lazy="true" cascade="all">
- <key column="team_id"></key>
- <one-to-many class="entity.Student"/>
- </set>
- </class>
- </hibernate-mapping>
- </pre><br>
- <pre name="code" class="java"><?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="entity.Student" table="student">
- <id name="id" column="id" type="string">
- <generator class="uuid"></generator>
- </id>
- <property name="name" column="name" type="string"></property>
- <property name="cardId" column="cardId" type="string"></property>
- <property name="age" column="age" type="int"></property>
- <set name="courses" table="student_course" cascade="save-update">
- <key column="stu_id"></key>
- <many-to-many class="entity.Course" column="course_id">
- </many-to-many>
- </set>
- </class>
- </hibernate-mapping>
- </pre><br>
- <pre name="code" class="java"><?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="entity.Course" table="course">
- <id name="id" column="id" type="string">
- <generator class="uuid"></generator>
- </id>
- <property name="name" column="name" type="string"></property>
- <set name="students" table="student_course" cascade="save-update" inverse="true">
- <key column="course_id"></key>
- <many-to-many class="entity.Student" column="stu_id">
- </many-to-many>
- </set>
- </class>
- </hibernate-mapping>
- </pre><pre name="code" class="java">package entity;
- import org.hibernate.cfg.Configuration;
- import org.hibernate.tool.hbm2ddl.SchemaExport;
- /**
- *
- *
- *
- create table course (id varchar(255) not null, name varchar(255), primary key (id))
- create table student (id varchar(255) not null, name varchar(255), cardId varchar(255), age integer, team_id varchar(255), primary key (id))
- create table student_course (stu_id varchar(255) not null, course_id varchar(255) not null, primary key (stu_id, course_id))
- create table team (id varchar(255) not null, teamName varchar(255), primary key (id))
- alter table student add index FK8FFE823BC2CDC4C9 (team_id), add constraint FK8FFE823BC2CDC4C9 foreign key (team_id) references team (id)
- alter table student_course add index FKB0A3729F7D75AAB2 (stu_id), add constraint FKB0A3729F7D75AAB2 foreign key (stu_id) references student (id)
- alter table student_course add index FKB0A3729F8BE0B449 (course_id), add constraint FKB0A3729F8BE0B449 foreign key (course_id) references course (id)
- *
- */
- public class CreateTable
- {
- public static void main(String[] args)
- {
- SchemaExport export = new SchemaExport(new Configuration().configure());
- export.create(true, true);
- }
- }
- </pre><br>
- <pre name="code" class="java">package entity;
- import java.util.List;
- import org.hibernate.Query;
- import org.hibernate.Session;
- import org.hibernate.Transaction;
- public class Test {
- public static void main(String[] args) {
- test3();
- }
- static void save () {
- //课程
- Course math = new Course();
- math.setName("math");
- Course english = new Course ();
- english.setName("english");
- Course chinese = new Course();
- chinese.setName("chinese");
- Course music = new Course ();
- music.setName("music");
- //学生
- Student zhangsan = new Student ();
- zhangsan.setName("zhangsan");
- zhangsan.setCardId("111");
- zhangsan.setAge(20);
- Student lisi = new Student ();
- lisi.setName("lisi");
- lisi.setCardId("222");
- lisi.setAge(21);
- Student wangwu = new Student ();
- wangwu.setName("wangwu");
- wangwu.setAge(22);
- wangwu.setCardId("333");
- //班级
- Team team1 = new Team ();
- team1.setTeamName("team1");
- Team team2 = new Team ();
- team2.setTeamName("team2");
- //关联
- zhangsan.getCourses().add(math);
- zhangsan.getCourses().add(music);
- lisi.getCourses().add(math);
- lisi.getCourses().add(chinese);
- lisi.getCourses().add(english);
- team1.getStudents().add(zhangsan);
- team1.getStudents().add(wangwu);
- team2.getStudents().add(lisi);
- Session session = HibernateUtil.getSession();
- Transaction tx = null;
- try {
- tx = session.beginTransaction();
- session.save(team1);
- session.save(team2);
- tx.commit();
- }catch (Exception ex) {
- ex.printStackTrace();
- if (null != ex) {
- tx.rollback();
- }
- }
- }
- static void test () {
- Session session = HibernateUtil.getSession();
- Transaction tx = session.beginTransaction();
- try {
- tx = session.beginTransaction();
- /*
- * 如果查询的是整个类表示一个Student(from Student s)对象,否则就是离散的值
- */
- Query query = session.createQuery("select s.name ,s.age from Student s");
- List list = query.list();
- for (int i = 0;i < list.size();i++) {
- Object[] obj = (Object[])list.get (i);
- System.out.println(obj[0]+":"+obj[1]);
- }
- tx.commit();
- }catch (Exception ex) {
- ex.printStackTrace();
- if (null != ex) {
- tx.rollback();
- }
- }
- }
- static void test2 () {
- Session session = HibernateUtil.getSession();
- Transaction tx = session.beginTransaction();
- try {
- tx = session.beginTransaction();
- Query query = session.createQuery("select new Student (s.name,s.age) from Student s");
- List list = query.list();
- for (int i = 0;i < list.size();i++) {
- Student student = (Student)list.get(i);
- System.out.println(student.getName()+":"+student.getAge());
- }
- /*
- *会发送sql语句
- *
- */
- Student student2 = (Student) session.get(Student.class, "8a68a9583eef4170013eef4171c60002");
- System.out.println("student2="+student2);
- tx.commit();
- }catch (Exception ex) {
- ex.printStackTrace();
- if (null != ex) {
- tx.rollback();
- }
- }
- }
- //内连接
- /**
- *
- *
- *
- */
- static void test3() {
- Session session = HibernateUtil.getSession();
- Transaction tx = session.beginTransaction();
- try {
- tx = session.beginTransaction();
- Query query = session.createQuery("from Team t inner join t.students s ");
- List list = query.list();
- for (int i = 0;i < list.size();i++) {
- Object ob[] = (Object[])list.get(i);
- Team team = (Team)ob[0];
- Student stu = (Student)ob[1];
- System.out.println(team.getId()+":"+stu.getId());
- }</pre><pre name="code" class="java"><pre name="code" class="java"><span style="white-space:pre"> </span>不会发送sql语句<span style="white-space:pre"> </span></pre><pre name="code" class="java"><span style="white-space:pre"> </span>Student student2 = (Student) session.get(Student.class, "8a68a9583eef4170013eef4171c60002");
- System.out.println("student2="+student2);</pre>tx.commit();}catch (Exception ex) {ex.printStackTrace();if (null != ex) {tx.rollback();}}}}
- <pre></pre>
- <pre name="code" class="java">--------------------------------------------------------------------------------------------------------------</pre><pre name="code" class="java"><pre></pre>
- <p></p>
- <pre></pre>
- <p></p>
- <pre name="code" class="java">package entity;
- import java.util.HashSet;
- import java.util.Set;
- public class Course
- {
- private String id;
- private String name;
- private Set<Student> students = new HashSet<Student>();
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public Set<Student> getStudents()
- {
- return students;
- }
- public void setStudents(Set<Student> students)
- {
- this.students = students;
- }
- }
- </pre><pre name="code" class="java">package entity;
- import java.util.HashSet;
- import java.util.Set;
- public class Student
- {
- private String id;
- private String cardId;
- private int age;
- private String name;
- private Set<Course> courses = new HashSet<Course>();
- private Team team;
- public Student()
- {
- }
- public Student(String name, int age)
- {
- this.age = age;
- this.name = name;
- }
- public Team getTeam() {
- return team;
- }
- public void setTeam(Team team) {
- this.team = team;
- }
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getName()
- {
- return name;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public Set<Course> getCourses()
- {
- return courses;
- }
- public void setCourses(Set<Course> courses)
- {
- this.courses = courses;
- }
- public String getCardId()
- {
- return cardId;
- }
- public void setCardId(String cardId)
- {
- this.cardId = cardId;
- }
- public int getAge()
- {
- return age;
- }
- public void setAge(int age)
- {
- this.age = age;
- }
- }
- </pre><br>
- <pre name="code" class="java">package entity;
- import java.util.HashSet;
- import java.util.Set;
- public class Team
- {
- private String id;
- private String teamName;
- @SuppressWarnings("unchecked")
- private Set students = new HashSet();
- public String getId()
- {
- return id;
- }
- public void setId(String id)
- {
- this.id = id;
- }
- public String getTeamName()
- {
- return teamName;
- }
- public void setTeamName(String teamName)
- {
- this.teamName = teamName;
- }
- @SuppressWarnings("unchecked")
- public Set getStudents()
- {
- return students;
- }
- @SuppressWarnings("unchecked")
- public void setStudents(Set students)
- {
- this.students = students;
- }
- }
- </pre><br>
- <pre name="code" class="java"><?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="entity.Course" table="course">
- <id name="id" column="id" type="string">
- <generator class="uuid"></generator>
- </id>
- <property name="name" column="name" type="string"></property>
- <set name="students" table="student_course" cascade="save-update" inverse="true">
- <key column="course_id"></key>
- <many-to-many class="entity.Student" column="stu_id">
- </many-to-many>
- </set>
- </class>
- </hibernate-mapping>
- </pre><br>
- <pre name="code" class="java"><?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="entity.Student" table="student">
- <id name="id" column="id" type="string">
- <generator class="uuid"></generator>
- </id>
- <property name="name" column="name" type="string"></property>
- <property name="cardId" column="cardId" type="string"></property>
- <property name="age" column="age" type="int"></property>
- <set name="courses" table="student_course" cascade="save-update">
- <key column="stu_id"></key>
- <many-to-many class="entity.Course" column="course_id">
- </many-to-many>
- </set>
- <many-to-one name="team" class = "entity.Team" fetch = "select" column = "team_id"></many-to-one>
- </class>
- </hibernate-mapping>
- </pre><br>
- <pre name="code" class="java"><?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="entity.Team" table="team">
- <id name="id" column="id" type="string">
- <generator class="uuid"></generator>
- </id>
- <property name="teamName" column="teamName" type="string"></property>
- <set name="students" inverse="true" lazy="true" cascade="all">
- <key column="team_id"></key>
- <one-to-many class="entity.Student"/>
- </set>
- </class>
- </hibernate-mapping>
- </pre><br>
- <pre name="code" class="java">package entity;
- import org.hibernate.cfg.Configuration;
- import org.hibernate.tool.hbm2ddl.SchemaExport;
- /**
- *
- *
- *
- create table course (id varchar(255) not null, name varchar(255), primary key (id))
- create table student (id varchar(255) not null, name varchar(255), cardId varchar(255), age integer, team_id varchar(255), primary key (id))
- create table student_course (stu_id varchar(255) not null, course_id varchar(255) not null, primary key (stu_id, course_id))
- create table team (id varchar(255) not null, teamName varchar(255), primary key (id))
- alter table student add index FK8FFE823BC2CDC4C9 (team_id), add constraint FK8FFE823BC2CDC4C9 foreign key (team_id) references team (id)
- alter table student_course add index FKB0A3729F7D75AAB2 (stu_id), add constraint FKB0A3729F7D75AAB2 foreign key (stu_id) references student (id)
- alter table student_course add index FKB0A3729F8BE0B449 (course_id), add constraint FKB0A3729F8BE0B449 foreign key (course_id) references course (id)
- *
- */
- public class CreateTable
- {
- public static void main(String[] args)
- {
- SchemaExport export = new SchemaExport(new Configuration().configure());
- export.create(true, true);
- }
- }
- </pre><br>
- <pre name="code" class="java">package entity;
- import java.util.List;
- import org.hibernate.Hibernate;
- import org.hibernate.Query;
- import org.hibernate.Session;
- import org.hibernate.Transaction;
- public class Test {
- public static void main(String[] args) {
- test();
- }
- static void test () {
- Session session = HibernateUtil.getSession();
- Transaction tx = session.beginTransaction();
- try {
- tx = session.beginTransaction();
- /*第一种方式
- Query query = session.createQuery("from Student s where s.team=:team and s.age <= 22");
- query.setString("team", "8a68a9583eef4170013eef4171b70001");
- List list = query.list();
- */
- /*第二种方式
- Team team = (Team)session.get(Team.class, "8a68a9583eef4170013eef4171b70001");
- Query query = session.createQuery("from Student s where s.team=:team and s.age <= 22");
- query.setParameter("team", team,Hibernate.entity(Team.class));
- List list = query.list();
- */
- /*第三种方式
- *
- * Team team = (Team)session.get(Team.class, "8a68a9583eef4170013eef4171b70001");
- Query query = session.createQuery("from Student s where s.team=:team and s.age <= 22");
- query.setEntity("team", team);
- List list = query.list();
- */
- Team team = (Team)session.get(Team.class, "8a68a9583eef4170013eef4171b70001");
- Query query = session.createFilter(team.getStudents(), "where age < 22");
- List list = query.list();
- for (int i = 0;i < list.size();i++) {
- Student student = (Student) list.get(i);
- System.out.println(student.getName());
- }
- tx.commit();
- }catch (Exception ex) {
- ex.printStackTrace();
- if (null != ex) {
- tx.rollback();
- }
- }
- }
- }
- </pre><br>
- <pre name="code" class="java">package entity;
- import java.util.List;
- import org.hibernate.Criteria;
- import org.hibernate.Session;
- import org.hibernate.Transaction;
- import org.hibernate.criterion.Order;
- import org.hibernate.criterion.Restrictions;
- public class Test2 {
- public static void main(String[] args) {
- test4 ();
- }
- public static void test () {
- Session session = HibernateUtil.getSession();
- Transaction tx = session.beginTransaction();
- try {
- Criteria criteria = session.createCriteria(Student.class).add(Restrictions.between("age", 20, 22));
- List list = criteria.list();
- for (int i = 0;i < list.size();i++) {
- Student student = (Student) list.get(i);
- System.out.println(student.getName());
- }
- tx.commit();
- }catch (Exception ex) {
- ex.printStackTrace();
- if (null != ex) {
- tx.rollback();
- }
- }
- }
- public static void test2 () {
- Session session = HibernateUtil.getSession();
- Transaction tx = session.beginTransaction();
- try {
- Criteria criteria = session.createCriteria(Student.class).add(Restrictions.like("name", "z%"));
- List list = criteria.list();
- for (int i = 0;i < list.size();i++) {
- Student student = (Student) list.get(i);
- System.out.println(student.getName());
- }
- tx.commit();
- }catch (Exception ex) {
- ex.printStackTrace();
- if (null != ex) {
- tx.rollback();
- }
- }
- }
- public static void test3 () {
- Session session = HibernateUtil.getSession();
- Transaction tx = session.beginTransaction();
- try {
- String name[] = {"zhangsan","lisi"};
- Criteria criteria = session.createCriteria(Student.class).add(Restrictions.in("name", name));
- List list = criteria.list();
- for (int i = 0;i < list.size();i++) {
- Student student = (Student) list.get(i);
- System.out.println(student.getName());
- }
- tx.commit();
- }catch (Exception ex) {
- ex.printStackTrace();
- if (null != ex) {
- tx.rollback();
- }
- }
- }
- public static void test4 () {
- Session session = HibernateUtil.getSession();
- Transaction tx = session.beginTransaction();
- try {
- Criteria criteria = session.createCriteria(Student.class).addOrder(Order.desc("age"));
- List list = criteria.list();
- for (int i = 0;i < list.size();i++) {
- Student student = (Student) list.get(i);
- System.out.println(student.getName()+":"+student.getAge());
- }
- tx.commit();
- }catch (Exception ex) {
- ex.printStackTrace();
- if (null != ex) {
- tx.rollback();
- }
- }
- }
- }
- </pre><br>
- <br>
- <p></p>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- </pre></pre>