马士兵hibernate文档 (个人完善版)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

3.
hibernate.hbm2ddl.auto :
在SessionFactory 创建时,自动检查数据库结构,或者将数据库schema 的DDL 导出到数据库。

使用create-drop 时,在显式关闭SessionFactory 时,将删除掉数据库schema。

例如:validate | update | create | create-drop
create :如果没有表就创建
update :如果表结构更新,就更新
validate :每次插入表的时候看看表结构有没有更新。

理论上是先建类后建表:这个时候只要你的类建好了,可以跨数据库。

实际中先建表比先建类多,建好表以后要对数据库进行优化,比如建索引,建试图,各种各样的优化。

project\etc目录下面有很多示例性的文档,log4j的文档就在那个下面。

SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); SessionFactory的建立是很耗费时间的,应该像连接池一样,只建立一次,以后要用就直接从那用。

Hibernate文档建议我们自己写一个辅助类,用单例来做。

JUnit的一个bug:
@BeforeClass
public 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 不需要的字段的设置
@Transient
public 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,默认的是native
increment(很少用)
用于为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;
}
@Override
public boolean equals(Object o) {
if(o instanceof StudentPK) {
StudentPK pk = (StudentPK)o;
if(this.id == pk.getId() && .equals(pk.getName())) {
return true;
}
}
return false;
}
@Override
public 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状态,就不发语句了。

session.getTransaction().commit();
}
缓存:本来东西在硬盘上的,现在在内存中开了一块区域,用来方便读取我们想要提高读取效率的引用。

@onetonoe//仅仅是@onetonoe产生的外键名字为Wife_ID,这时需要指定对应表中外键的名字
@JoinColum(name=”WifeID”)
一对一双向外键关联:单向和双向在数据库里面没有区别,在java程序里面有区别,双向可以通过wife找到husband也可通过husband找到wife @Entity
public class Wife {
private int id;
private String name;
private Husband husband;
@OneToOne(mappedBy="wife")//告诉hibernate,在这里不需要创建外键,只需要关联到Husband类里面的wife属性。

public Husband getHusband() {
return husband;
}
public void setHusband(Husband husband) { this.husband = husband;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
@Entity
public class Husband {
private int id;
private String name;
private Wife wife;
@Id
@GeneratedValue
public int getId() {
return id;
}
public String getName() {
return name;
}
@OneToOne
@JoinColumn(name="wifeId")
public Wife getWife() {
return wife;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
= name;
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
一对一单向关联,联合主键关联。

(用得很少)
这里的joincolumns是想改里面的外键的名字。

@Entity
public class Husband {
private int id;
private String name;
private Wife wife;
@Id
@GeneratedValue
public int getId() {
return id;
}
public String getName() {
return name;
}
@Embedded
public Wife getWife() {
return wife;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
= name;
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
public class Wife {
private String wifeName;//小心与Husband表里面的字段同名,可在get方法上加@column在数据库里面改变名字private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getWifeName() {
return wifeName;
}
public void setWifeName(String name) { this.wifeName = name;
}
}
第一范式:要有主键,列不可分。

第二范式:联合主键存在的时候不能存在部分依赖。

第三范式:不能存在传递依赖。

多对一单向:
@Entity
@Table(name="t_user")
public class User {
private int id;
private String name;
private Group group;
@ManyToOne//只要写个ManyToOne就行了
public Group getGroup() {
return group;
}
public void setGroup(Group group) { this.group = group;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
@Entity
@Table(name="t_group")//group是关键字,所以要改名字
public class Group {
private int id;
private String name;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
一对多单向:
@Entity
@Table(name="t_group")
public class Group {
private int id;
private String name;
private Set<User> users = new HashSet<User>();//用set比较好,因为不会有重复@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
@OneToMany
@JoinColumn(name="groupId")//如果没有JoinColumn,会当成多对多的情况,产生中间表public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) { ers = users;
}
}
@Entity
@Table(name="t_user")
public class User {
private int id;
private String name;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
多对多单向关联:
@Entity
public class Teacher {
private int id;
private String name;
private Set<Student> students = new HashSet<Student>();
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
@ManyToMany
@JoinTable(name="t_s",//如果想改变中间表的表名
joinColumns={@JoinColumn(name="teacher_id")},//如果想改变字段名
inverseJoinColumns={@JoinColumn(name="student_id")}//如果想改变另一张表的字段名)
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
@Entity
public class Student {
private int id;
private String name;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
多对多双向关联:
@Entity
public class Student {
private int id;
private String name;
private Set<Teacher> teachers = new HashSet<Teacher>();
@ManyToMany(mappedBy="students")//只要在这边加一个mappedBy就行了public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
@Entity
public class Teacher {
private int id;
private String name;
private Set<Student> students = new HashSet<Student>();
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
@ManyToMany
@JoinTable(name="t_s",
joinColumns={@JoinColumn(name="teacher_id")},
inverseJoinColumns={@JoinColumn(name="student_id")}
)
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) { this.students = students;
}
}
如果只写OrderBy 则按照主键排序
用in还是exists,用exists 因为它的执行效率高~
qbc:query by criterial
qbe:query by example
java语言在语法级别上是没有内存泄漏的,因为他有垃圾回收器帮忙回收,但是如果你写程序的时候用到了一些资源,一定要注意回收,比如说你用到了连接池打开了链接一定要注意关闭,不然他在内存中就老开着。

比如说你打开了文件,一定要注意关闭,不关闭的话他就不会调用本地的资源把它关闭。

这个其实是在本地的代码里面有,因为这样相当于java调用了c,c调用了Windows的API。

c语言是需要手动调用内存的,所以这其实是java引起的。


以在语法级别上其实没有,但是在你实际中写程序的时候很有可能引起内存泄漏。

public void testQBC() {
Session session = sf.openSession();
session.beginTransaction();
//criterion 标准/准则/约束
Criteria c = session.createCriteria(Topic.class) //from Topic
.add(Restrictions.gt("id", 2)) //greater than = id > 2
.add(Restrictions.lt("id", 8)) //little than = id < 8
.add(Restrictions.like("title", "t_"))
.createCriteria("category")
.add(Restrictions.between("id", 3, 5)) //category.id >= 3 and category.id <=5
;
//DetachedCriterea
for(Object o : c.list()) {
Topic t = (Topic)o;
System.out.println(t.getId() + "-" + t.getTitle());
}
session.getTransaction().commit();
session.close();
}
public void testQBE() {
Session session = sf.openSession();
session.beginTransaction();
Topic tExample = new Topic();
tExample.setTitle("T_");
Example e = Example.create(tExample)
.ignoreCase().enableLike();
Criteria c = session.createCriteria(Topic.class)
.add(Restrictions.gt("id", 2))
.add(Restrictions.lt("id", 8))
.add(e)
;
for(Object o : c.list()) {
Topic t = (Topic)o;
System.out.println(t.getId() + "-" + t.getTitle());
}
session.getTransaction().commit();
session.close();
}
1+N问题:在一个对象里面关联了另一个对象,同时fetchType为eager,比如说最典型的是manytoone。

要取many里面的对象的时候,这些对象都会单独发一条sql语句出来。

本来发一条sql语句就行的,结果发了1+N条语句。

解决方案一:把这个对象的fetchType设为lazy,lazy并不是不发出了,而是在用到的时候再发出。

第二种方法:betchsize,一种不太正规的解决方案,发sql语句的次数为:总共有多少对象/betchsize次。

第三种方法:join fetch 默认的qbc就是采用这种。

丢失更新:只有在不支持事物的数据库里才会出现丢失更新。

脏读:你读到了别的事物还没有提交的数据。

脏读:读了别的事物没有提交的数据
不可重复读:同一个事物里面前前后后读出来的数据不一样。

事物的隔离级别越高,效率就越低。

因为他要检查,要上锁。

一般把事物的隔离机制设为read-committed,在通过程序来处理别的情况
取2进制的好处,提高效率
CRUD权限
使用乐观锁与悲观锁:除非你对效率要求很严格。

否则在数据库里面直接设定一个repeatableread就行了
悲观锁是属于数据库的锁,乐观锁自己设一个版本字段,每次更新的时候都会检查一下。

设定悲观锁:Account a = (Account)session.load(Account.class, 1, LockMode.UPGRADE); 设定乐观锁:
@Entity
public class Account {
private int id;
private int balance;
private int version;
@Version//说明这个字段是专门记录版本的
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}。

相关文档
最新文档