Hibernate
对象的三种状态
Hibernate 中Java对象的状态
1.临时状态 (transient)
特征:
1】不处于Session 缓存中
2】数据库中没有对象记录
Java如何进入临时状态
1】通过new语句刚创建一个对象时
2】当调用Session 的delete()方法,从Session 缓存中删除一个对象时。
2.持久化状态(persisted)
特征:
1】处于Session 缓存中
2】持久化对象数据库中设有对象记录
3】Session 在特定时刻会保持二者同步
Java如何进入持久化状态
1】Session 的save()把临时-》持久化状态
2】Session 的load(),get()方法返回的对象
3】Session 的find()返回的list集合中存放的对象
4】Session 的update(),saveOrupdate()使游离-》持久化
3.游离状态(detached)
特征:
1】不再位于Session 缓存中
2】游离对象由持久化状态转变而来,数据库中可能还有对应记录。
Java如何进入持久化状态-》游离状态
1】Session 的close()方法
2】Session 的evict()方法,从缓存中删除一个对象。提高性能。少用。
顺序问题
在实际应用中,一般是先建表后用反向工程生成类。
slf(日志)
它是一套规范。其实现有这几种:slf4j-nodep,log4j,jdk logging api,apachecommons-logging
Log4J日志环境搭建
1、 slf4j-api-1.6.1.jar是一个规范,需要加log4j-1.2.15.jar,不可以有slf4j-nop-1.6.1.jar(slf自己的实现)文件,否则会有两个实现,出错!
2、 添加slf4j-1.6.1目录下的slf4j-log4j12-1.6.1.jar(slf接口转换为log4j接口)
3、 从hibernate-distribution-3.3.2.GA-dist\project\etc目录下复制log4j.properties文件到src下。
4、 可以修改log4j.properties文件,按自己要求输出信息。
注解位置
应放在get方法上。放在字段上的话破坏封装。不能放在set方法上面。
hbm2ddl(查文档)
四中状态:create:每次都将原来的删除,重新建新表
update:检查是否发生变化,变化就更新
ID生成策略
1、 XML
标签id的子标签:<generator class="native"/>
常用的类型:native、uuid、sequence、identity
2、 Annotation
@GeneratedValue,默认为aoto,也可以这么写:@GeneratedValue(strategy=GenerationType.AUTO)
可指定生成器Generator(在Oracle中自动生成的序列名为hibernate_sequence,指定生成器就可命名序列)。两种生成器:
1)@SequenceGenerator
2)@TableGenerator (跨平台)
这两种生成器需写在类上,在主键字段上指定策略为sequence并用generator引用生成器名
联合字段做主键(查文档)不重要
1、Annotation
1、将组件类注解为@Embeddable,并将组件的属性(实体类中而非主键类)注解为@Id
2、将组件的属性注解为@EmbeddedId
3、将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id
2、XML
<composite-id……>
<key-property……/>
<key-property……/>
</composite-id>
openSession()和getCurrentSession()的区别
1、前者需要手动关闭session,后者不需要手动关闭session,在线程消亡后自动关闭。
2、前者永远都打开新的session,后者先从上下文找,如果没有找到则产生新的session,在事务提交之前永远都是同一个session。
3、getCurrentSession()可以用来界定事务边界。
几种类型属性的映射:
@Transient//透明,意思是说不映射到表
1、XML:
指定其type
2、Annotation:
枚举类型:
@Enumerated(EnumType.STRING)
日期类型:
@Temporal(TemporalType.DATE)
映射类型
核心开发接口
1、 Configuration管理配置文件
Config() buildSessionFactoty()
2、 sessionFactory管理多个连接池,产生session
3、 Session可以理解为一个数据库连接
4、 AnnotationConfiguration 用注解@来映射的时候要newAnnotationConfiguration();
5、 hibernate.cfg.xml文件可以直接放在src下,配置的时候可以直接用config(),不需要参数;也可以放在包下面,这时候就要将包的路径加入,如:com/bjsxt/hibernate/hibernate.cfg.xml。其他的文件类似的效果。
6、 hibernate中的mapping标签,当用xml文件的时候:resource=” com/bjsxt/hibernate/hibernate.cfg.xml”;当用注解@的时候:class=“com.bjsxt.hibernate.Teacher”,要用完整的类名。
CRUD(时刻注意对象的状态)
get和load都是先从缓存找,如果没有,才去数据库中找。
1、get()和load()的区别:
1、 get()是直接从数据库加载,不会延迟,而load()获取到的是代理对象,只有当用到对象中的内容时才会发送sql语句。
2、 get()方法将从数据库加载的数据存放到对象中,事务提交后对象中还可以取到值
3、 如果未能发现符合条件的记录,Hibernate get方法返回null,而load方法会抛出一个ObjectNotFoundException。
1) 在使用getCurrentSession()方法时,load()方法事务提交后就不能获取值,会报LazyInitializationException异常,因为此时线程已经消亡,找不到session,不能初始化代理。因为getCurrentSession会自动close。
2) 在使用openSession()时,在session.close()之前,load()方法获取的代理对象中的内容还可以使用。
3) 总之一句话:不管是openSession()还是getCurrentSession()。在session关闭之后,load()方法获取的代理对象中的内容不可以使用,异常,get()可以。
update():
注意:session.get()时,对象状态为persistent,在事务提交之前如果更改了对象的属性值(调用set方法),事务提交后会自动发送一条update语句(即使没有session.update(*))。保持缓存和数据库的同步。
如果个别字段不需要更改:
1、 可以注解@Column(updatable = false)或XML中property标签属性update=”false”
2、 XML中指定class标签的属性dynamic-update=”true”
3、 跨session:(上个session1.get()的对象obj)在session2中可以这样调用session2.merge(obj),意思是合并。(了解即可)
2、saveOrUpdate()
3、clear() 清空session缓存
4、flush() 强制让缓存内容和数据库同步,用session.flushMode()方法指定flush时间,性能调优
5、find 过时
SchemaExport
可以在应用程序中创建表。
newSchemaExport(new Configuration().configure()).create(true,true);
关系映射(文档里有很全的例子说明)
一个异常:Exceptionin thread "main" java.lang.NoSuchMethodError:javax.persistence.OneToOne.orphanRemoval()Z
原因hibernate的jar包里面加了那个ejb3的jar包与JPA包冲突 ejb删就OK了。
对象之间的关系:
1、 多对多
2、 多对一
3、 一对一
严格来说只有一个那就是 多对多
多对一是多对多的一种特殊情况
一对一是多对一的一种特殊情况
数据库的表和表之间只有一种关系:外键
1、 一对一
1) 单向外键关联:
Annotation:在持有外键引用的类中:@OneToOne可用 @JoinColumn指定关联字段
XML:<many-to-onename="wife" column="wifeId" unique="true"/>
2) 双向外键关联:
Annotation:在两个实体类中都注解:@OneToOne ,mappedBy 意思是说对方是主导,由对方引用自己。
XML:<many-to-onename="wife" column="wifeId" unique="true"/>
被引用的实体类配置文件:
<one-to-onename="husband" property-ref="wife"></one-to-one>
3) 单向主键关联:
Annotation: @OneToOne,@PrimaryKeyJoinColumn
XML:通常使用一个特定的id 生成器
3) 联合主键关联
@joinColumns(
{
@joinColumn(name=”wifeId”,referencedColumnName=”id”),
@joinColumn(name=”wifeName”,referencedColumnName=”name”)
}
)
2、 组件映射(只生成一张表)
1) Annotation:一个实体类持一个组件类的外键引用,在被引用组件对象的get方法上@Embedded,配置文件中只映射持有引用的那个类。
Xml:<componentname="wife">
<propertyname="wifeId"></property>
<propertyname="wifeName"></property>
</component>
3、 多对一
建表时,可以在多的一方持有一的外键,会减少冗余。
1) 多对一单向关联:
Annotation:在多的一方@ManyToOne
Xml:<many-to-one name=”person” />
2) 一对多单向关联:
Annotation:在一的一方@OneToMany
@JoinColumn(name="personId"),”personId”是随便写的。如果没有@JoinColumn则会生成一个中间表。
Xml: <setname="dreams">
<keycolumn="personId"></key>
<one-to-manyclass="Dream"/>
</set>
3) 多对一,一对多双向关联:
Annotation: @ManyToOne
@JoinColumn(name="personId")
在一的一方:
@OneToMany(mappedBy="person")
Xml:在一的一方:
<set name="dreams">
<keycolumn="personId"></key>
<one-to-many class="Dream"/>
</set>
在多的一方:<many-to-onename="person" column="personId" />
4、 多对多
1) 多对多单向关联:
Annotation: @ManyToMany
@JoinTable(name="t_s",
joinColumns={@JoinColumn(name="studentId")},
inverseJoinColumns={@JoinColumn(name="teacherId")}
)
Xml:<set name="teachers" table="t_s">
<keycolumn="studentId"></key>
<many-to-manyclass="Teacher" column="teacherId"/>
</set>
2)多对多双向关联:
说下Hibernate的缓存机制:
Hibernate缓存的作用:
Hibernate是一个持久层框架,经常访问物理数据库,为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据
Hibernate缓存分类:
Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存
Hibernate一级缓存又称为“Session的缓存”,它是内置的,意思就是说,只要你使用hibernate就必须使用session缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。在第一级缓存中,持久化类的每个实例都具有唯一的OID。
Hibernate二级缓存又称为“SessionFactory的缓存”,由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory不会启用这个插件。
什么样的数据适合存放到第二级缓存中?
1 很少被修改的数据
2 不是很重要的数据,允许出现偶尔并发的数据
3 不会被并发访问的数据
4 常量数据
不适合存放到第二级缓存的数据?
1经常被修改的数据
2 .绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
3 与其他应用共享的数据。
如何优化Hibernate?
1.使用双向一对多关联,不使用单向一对多
2.灵活使用单向一对多关联
3.不用一对一,用多对一取代
4.配置对象缓存,不使用集合缓存
5.一对多集合使用Bag,多对多集合使用Set
6. 继承类使用显式多态
7. 表字段要少,表关联不要怕多,有二级缓存撑腰