3.hibernate.hbm2ddl.auto :在SessionFactory 创建时,自动检查数据库结构,或者将数据库schema 的DDL 导出到数据库。
使用create-drop 时,在显式关闭SessionFactory 时,将删除掉数据库schema。
例如:validate | update | create | create-dropcreate :如果没有表就创建update :如果表结构更新,就更新validate :每次插入表的时候看看表结构有没有更新。
理论上是先建类后建表:这个时候只要你的类建好了,可以跨数据库。
实际中先建表比先建类多,建好表以后要对数据库进行优化,比如建索引,建试图,各种各样的优化。
project\etc目录下面有很多示例性的文档,log4j的文档就在那个下面。
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); SessionFactory的建立是很耗费时间的,应该像连接池一样,只建立一次,以后要用就直接从那用。
Hibernate文档建议我们自己写一个辅助类,用单例来做。
JUnit的一个bug:@BeforeClasspublic static void beforeClass() {sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();}在这句话的时候配置文件如果有的时候写错了,她悄悄把错误隐藏起来了。
解决的方法:可以对这句话加try catch块8.表名和类名不一致的时候:@Entity@Table(name="_teacher")public class Teacher {10字段名和属性名不一致的时候@Column(name="_name")public String getName() {return name;}11 不需要的字段的设置@Transientpublic String getYourWifeName() {return yourWifeName;}12 映射指定的时间日期@Temporal(TemporalType.TIME)public Date getBirthDate() {return birthDate;}在注解里面如果一个注解的属性名字叫value,你可以不写,直接写后面的值,如@Temporal(value=“TemporalType.TIME”)可写成上面的那样。
如果不写会把时间日期都放到表里面指定时间时默认TemporalType.TIMESTAMP还有time 和date 不过最常用的还是默认的。
13注意映射枚举类型用habernate xml的方式很麻烦在设定枚举时:以字符串方式显示:EnumType.STRING 以数字书序显示:EnumType.ORDINAL@Enumerated(EnumType.STRING)public Gender getGender() {return gender;}自增Mysql autoincreatment Oracle sequence如果将来的程序想跨数据库平台选native或uuid@GenerateValue注意是javax.persistence里的value,默认的是nativeincrement(很少用)用于为long, short 或者int 类型生成唯一标识。
只有在没有其他进程往同一张表中插入数据时才能使用。
在集群下不要使用。
identity(用得较多)对DB2,MySQL,MS SQL Server,Sybase 和HypersonicSQL 的内置标识字段提供支持。
返回的标识符是long,short 或者int 类型的。
sequence(用得较多)在DB2,PostgreSQL,Oracle,SAP DB,McKoi 中使用序列(sequence),而在Interbase 中使用生成器(generator)。
返回的标识符是long,short 或者int 类型的。
hilo使用一个高/低位算法高效的生成long,short 或者int 类型的标识符。
给定一个表和字段(默认分别是hibernate_unique_key 和next_hi)作为高位值的来源。
高/低位算法生成的标识符只在一个特定的数据库中是唯一的。
uuid用一个128-bit 的UUID 算法生成字符串类型的标识符,这在一个网络中是唯一的(使用了IP 地址)。
UUID 被编码为一个32 位16 进制数字的字符串。
guid在MS SQL Server 和MySQL 中使用数据库生成的GUID 字符串。
Native(用得较多)根据底层数据库的能力选择identity、sequence 或者hilo 中的一个。
在Oracle里面表名不能以下划线开头@Id@GeneratedValue (默认的是auto相当于native,在jpa1.0中,只有四种ID生成策略,下面的b、c、d、e)这种方式虽然是跨平台的,但是由于各种数据库生成数据的方式不同,生成的数据会有所不同。
如果要在跨平台的数据库中生成的方式也相同,可以采用e。
但极少会出现跨数据库平台的情况。
用auto的方式在Oracle中sequence生成策略只能起名hibernate sequence,不能起别的名字。
跨数据库平台的情况:自己写了一个给别人用的类库,这个类库可以跨平台。
public int getId() {return id;}@Id@GeneratedValue(strategy=GenerationType.TABLE, generator="Teacher_GEN")这里也可指定生成别的方式。
GenerationType可以在javaee文档里面找public int getId() {return id;}在Oracle中生成方式如果是sequence,可以指定一个sequence的名字。
@SequenceGenerator(name="teacherSEQ", sequenceName="teacherSEQ_DB")public class Teacher {@Id@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="teacherSEQ")public int getId() {return id;}6、设计数据库的时候建立主键,能用一个字段就尽量用一个字段,不要用多个字段。
但是不可避免,有些数据库表别人已经设计好了,有两个字段作为主键,这时可以在hibernate中使用联合主键。
在程序中用到面向对象的思想,要建立一个主键类,并对该类实现serializable接口。
实现序列化的原因:出现这种情况:系统实现集群,很多台服务器对外服务,一台服务器当机了,正好有一部分属性在那边;另一种情况:如果内存满了,会用到虚拟内存(把硬盘上的一部分空间作为内存),有部分内容就要存到硬盘上去了。
重写equals和hashcode的原因:主键要保证唯一性,不仅在数据库中要保证,一系列的对象要放在内存中,也要有所区分。
所以一定要重写equals 和hashcode,而且逻辑不能乱写,不能用父类中的equals和hashcode。
要对比是否相同,首先要查hash表的hashcode,再与hashcode相同的对比。
public class StudentPK implements java.io.Serializable{private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) { = name;}@Overridepublic boolean equals(Object o) {if(o instanceof StudentPK) {StudentPK pk = (StudentPK)o;if(this.id == pk.getId() && .equals(pk.getName())) {return true;}}return false;}@Overridepublic int hashCode() {return .hashCode();}}getCurrentSession 和openSession 得到的不是同一个类,所以这两种方式不能混用。
有两种事物,一种是指针对数据库本身的不能处理分布式的事物.另外一种是JTA事物,能处理分布式的。
<property name="current_session_context_class">thread</property> tomcat不能使用这种:因为它没有相关的实现<property name="current_session_context_class">jta</property>public void testClear() {Session session = sessionFactory.getCurrentSession();session.beginTransaction();Teacher t = (Teacher)session.load(Teacher.class, 1);System.out.println(t.getName());session.clear();Teacher t2 = (Teacher)session.load(Teacher.class, 1);System.out.println(t2.getName());//如果没有clear,数据库里面就只有一条更新语句session.getTransaction().commit();}public void testFlush() {Session session = sessionFactory.getCurrentSession();session.beginTransaction();Teacher t = (Teacher)session.load(Teacher.class, 1);t.setName("tttt");session.flush();t.setName("ttttt");//如果没有flush,数据库里面就只有一条更新语句,如果用clear,就变成了transitant状态,就不发语句了。