背景为灰色的表示常用,熟记。
Hibernate 类型 |
Java类型 |
Oracle类型 |
type="java.lang.Long" |
Java.lang.Long |
NUMBER |
java.lang.String |
String |
Varchar2 |
java.lang.Double |
Double |
NUMBER |
java.sql.Timestamp |
Java.util.Date |
TIMESTAMP(6) |
type="java.lang.String" |
String |
CHAR(1) |
java.sql.Timestamp |
Java.util.Date |
TIMESTAMP(6) |
|
背景为灰色的表示常用,熟记。
2.1 hibernate mysql 基本类型映射
Hibernate 映射类型 |
Java 类型 |
标准 SQL 类型 |
大小和范围 |
integer 或者 int |
int 或者 java.lang.Integer |
INTEGER |
4 字节 |
long |
long Long |
BIGINT |
8 字节 |
short |
short Short |
SMALLINT |
2 字节 |
byte |
byte Byte |
TINYINT |
1 字节 |
float |
float Float |
FLOAT |
4 字节 |
double |
double Double |
DOUBLE |
8 字节 |
big_decimal |
java.math.BigDecimal |
NUMERIC |
NUMERIC(8,2)8 位 |
string |
char Character String |
CHAR(1) |
定长字符 |
string |
String |
VARCHAR |
变长字符串 |
boolean |
boolean Boolean |
BIT |
布尔类型 |
2.2 Java 时间和日期类型的 Hibernate 映射
映射类型 |
Java 类型 |
标准 SQL 类型 |
描述 |
date |
util.Date 或者 sql.Date |
DATE |
YYYY-MM-DD |
time |
Date Time |
TIME |
HH:MM:SS |
timestamp |
Date Timestamp |
TIMESTAMP |
YYYYMMDDHHMMSS |
calendar |
calendar |
TIMESTAMP |
YYYYMMDDHHMMSS |
配置、Jar 包等:
a) hibernateannotaion jar
b) ejb3persistence jar
c) hibernatecommon-annotations.jar
FAQ: @不给提示,配置eclipse属性信息contentassist-activation--加上@
通过 @Basic 可以声明属性的存取策略:
@Basic(fetch=FetchType.EAGER) 即时获取(默认的存取策略)
@Basic(fetch=FetchType.LAZY) 延迟获取
通过 @Temporal 定义映射到数据库的时间精度:
@Temporal(TemporalType=DATE) 日期
@Temporal(TemporalType=TIME) 时间
@Temporal(TemporalType=TIMESTAMP) 两者兼具
使用 @Column 映射到列
@Column(
name="columnName"; // 可选,列名(默认是属性名)
boolean unique() default false; // 可选,是否在该列上设置唯一约束(默认 false)
boolean nullable() default true; // 可选,是否可以为空
boolean insertable() default true; // 可选,该列是否作为生成insert语句中的一列
boolean updatable() default true; // 可选,该列是否作为生成update语句中的一列
String columnDefinition() default ""; // 可选,为这个特定列覆盖SQL DDL 片段(可能导致无法在不同数据库间移植)
String table() default ""; // 可选,定义对应的表,默认为主表
int length() default 255; //可选,列长度
int precision() default 0; // 可选,列十进制精度(decimalprecision)
int scale() default 0; // 可选,列十进制数范围(decimal scale)
public class Person {
@Column(name ="PERSONNAME", unique = true, nullable = false, updatable = true)
private String name;
@Column(name ="PHOTO", columnDefinition = "BLOB NOT NULL",secondaryTable="PER_PHOTO")
private byte[] picture;
}
必须实现 po层Serializable接口
5.1 xml格式的:
一方:
多方:
5.2 annotation方式的:
多方:
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privateInteger id;
privateString mname;
@ManyToOne
privateStudent student;
一方:
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privateInteger id;
privateString sname;
privateString pwd;
@OneToMany(mappedBy="student")
privateSet
6.1 xml格式的:
6.2 annotation格式的:
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privateInteger id;
privateString cname;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="student_id",unique=true)
privateStudent student;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privateInteger id;
privateString sname;
@OneToOne(mappedBy="student")
privateCourse course;
6.3 一对一主键关联
annotation格式的:
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privateInteger id;
privateString cname;
privateInteger age;
privateString des;
@OneToOne(cascade=CascadeType.ALL)
@PrimaryKeyJoinColumn
privateStudent student;
@Id
@GenericGenerator(name="cc",strategy="foreign",parameters={@Parameter(name="property",value="course")})
@GeneratedValue(generator="cc")
privateInteger id;
privateString sname;
privateInteger age;
privateString des;
@OneToOne(mappedBy="student",cascade=CascadeType.ALL)
privateCourse course;
7.1 xml格式的:
xml格式的:
7.2 annotation格式的:
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privateInteger id;
privateString mname;
@ManyToMany(mappedBy="moneys")
privateSet
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privateInteger id;
privateString sname;
privateString pwd;
@ManyToMany
privateSet
8.1不需要psersistence的字段
a) Annotation:@Transient
b) xml不写
8.2映射日期与时间类型,指定时间精度
a) Annotation:@Temporal(参数) 参数有3种只显示时间,只显示日期,时间日期都显示
//@Temporal(TemporalType.DATE) 只显示日期
//@Temporal(TemporalType.TIME) 只显示时间
//@Temporal(TemporalType.TIMESTAMP) 显示日期与时间
b) xml:指定 type
propertyname="name" type="time" />
其他常用的序列生成方式
这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当然,Hibernate提供了很多内置的实现。下面是一些内置生成器的快捷名字:
用于为long, short或者int类型生成唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。(补充:主键按数值顺序递增,此方式的实现机制为在当前实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候在此值上加1作为主键,可能产生的问题:如果当前有多个实例访问同一个数据库,那么由于各个实例都维持主键状态,不同实例可呢生成同样主键,从而造成主键重复异常,因此,如果同一个数据库有多个实例访问,此方式必须避免使用。)
在DB2,PostgreSQL,Oracle, SAP DB, McKoi中使用序列(sequence),而在Interbase中使用生成器(generator)。返回的标识符是long, short或者 int类型的。
用一个128-bit的UUID算法生成字符串类型的标识符。在一个网络中唯一(使用了IP地址)。UUID被编码为一个32位16进制数字的字符串。
根据底层数据库的能力选择identity, sequence 或者hilo中的一个。(详解:由hibernate根据数据库适配器中的定义,自动采用identify、hilo、sequence的其中一种作为主键生成方式)
@GeneratedValue
a) 自定义ID
b) AUTO(直接写 @GeneratedValue 相当如native)
i. 默认:对 MySQL,使用auto_increment
ii. 对 Oracle使用hibernate_sequence(名称固定)
c) IDENTITY(@GeneratedValue(strategy=GenerationType.IDENTITY))
d) SEQUENCE(@GeneratedValue(strategy=GenerationType.SEQUENCE))
i. @SequenceGenerator(可自定义在数据库生成指定的sequence名)
@Id
//在@GeneratedValue中增加 generator="teacherSEQ"
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="teacherSEQ")
//"teacherSEQ"为@SequenceGenerator的标识名
//"teacherSEQ_DB"为指定到数据库生成的Sequence名
@SequenceGenerator(name="teacherSEQ",sequenceName="teacherSEQ_DB")
public intgetId() {
returnid;
}
a) slf4j与log4j的关系:slf4j像是一个大管家,可以管理许多的日志框架,log4j是其中之一
b) 加入slf4j-log4j.jar,加入 log4j 的 jar 包,去掉 slf4-nop.jar
c) 从hibernate/project/etc目录 copy log4j.properties
show_sql
i. 将联合主键的属性提取出来,重新编写一个pojo类(原pojo类中的id,name要删除并新加入属性“StudentPK”)
public class StudentPKimplements Serializable {
privateString id;
privateString name;
… …
ii. 新建pojo类必须实现 java.io.Serializable序列化接口
iii. 新pojo类要重写equals和hashCode方法
@Override
public boolean equals(Object o) {
if(o instanceofStudentPk) {
StudentPk pk =(StudentPk)o;
if(this.id ==pk.getId() && this.name.equals(pk.getName())) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
returnthis.name.hashCode();
}
iv. 联合主键生成策略XML配置方法
i. 前三步与Xml方式前三步一样 都要建立新pojo类 都要实现Serializable接口 重写equals和hashCode方法.
ii. 方法1在新类前写@Embeddable,在原pojo类的新属性“TercherPK”的get方法前写@ld,如下
@ Embeddable
public class TeacherPK implements Serializable {
privateString id;
privateString name;
… …
@Entity
publicclass Teacher {
private TeacherPK teacherPK ;
@Id
public TeacherPK getTeacherPK(){
return teacherPK;
}
… …
iii. 方法2:@EmbeddedlD(*) 新pojo类无需加注解,只需在原pojo类新属性“TercherPK”的get方法前写@EmbeddedlD即可
iv. 方法3:@ld @IdClass(*) 新pojo类无需加注解,原pojo类的id,name属性保留不变,也无需新增“TercherPK”属性。 只在id,name的get方法前都加@Id,并在原pojo类前加“@IdClass(TeacherPK).class)”,如下
@Entity
@IdClass(TeacherPK.class)
public class Teacher {
private String id;
private String name;
@Id
public String getId() {
return id;
}
@Id
public String getName() {
return name;
}
a) AnnotationConfiguration
b) 进行配置信息的管理
c) 用来产生SessionFactory
d) 可以在configure方法中指定hibernate配置文件
e) 只气关注一个方法即:buildSessionFactory
1) 用来产生和管理Session
2) 通常情况下每个应用只需要一个SessionFactory
3) 除非要访间多个数据库的情况
4) 关注两个方法即:openSession getCurrentsession
i. open session每次都是新的,需要close
ii. getCurrentsession从上下文找,如果有,用旧的,如果没有,建新的
1. 用途,界定事务边界
2. 事务提交自动close
3. 上下文配置可参见xml文件中
4. current_session_context_class (jta、thread常用 managed、custom.Class少用)
a) thread 使用connection 但数据库连接管理事务
b)jta (全称java transaction api)-java分布式事务管理(多数据库访问)
jta由中间件提供(jboss WebLogic等,tomcat不支持)
a) 管理一个数据库的任务单元(简单说就是增 删 改 查)
b) 方法(CRUD)
i. get与load的区别
1. 不存在对应记录时表现不一样
2. load返回的是代理对象,等到真正用到对象的内容时才发出sql语句
3. get直接从数据库加载,不会延迟
ii. updates
1. 用来更新detached对象,更新完成后转为persistent状态
2. 更新transient对象会报错
3. 更新自己设定id的transient对象可以(数据库有对应记录)
4. persistent状态的对象只要设定(如:t.setName…)不同字段就会发生更新
5. 更新部分更改的字段
a)xml 设定property 标签的 update 属性,annotation 设定@Column 的 updatable
属性,不过这种方式很少用,因为不灵活
b)使用xml中的dynamic-update,JPA1.0 Annotation 没有对应的属性,hibernate 扩
展?
i. 同一个session可以,跨session不行,不过可以用merge()(不重要)
c)使用 HQL(EjBQL)(建议)
iii. clear方法
1.无论是load还是get,都会首先査找缓存(一级缓存),如果没有,才会去数据库査找
clear()方法可以强制清除session缓存
iv. flush()方法
1. 当session的事务提交后,会强制将内存(session缓存)与数据库同步.默认情况下是session的事务提交(commit)时才同步!
2. session的FlushMode设置,可以设定在什么时候同步缓存与数据库(很少用)
例如: session.setFlushMode(FlushMode.AUTO)
i. 有没有ID
ii. ID在数据库中有没有
iii. 在内存中有没有(session缓存)
a) transient:内存中一个对象,没ID,缓存中也没有
b) persistent:内存中有,缓存中有,数据库有(ID)
c) detached:内存有,缓存没有,数据库有,ID
1) 重点是equals,重写hashCode只是技术要求(为了提高效率)
2) 为什么要重写equals呢,因为在java的集合框架中,是通过equals来判断两个对象是否相等的.如果没有用到比较这些的,也可以不重写equals.
3) 在hibernate中,经常使用set集合来保存相关对象,而set集合是不允许重复的,但是下面的程序,判断一下运行结果:Set user = newHashSet();
user.add(newAddress("http://hi.baidu.com/yangwen_yw"));
user.add(newAddress("http://hi.baidu.com/yangwen_yw"));
System.out.println(user.size());
上面程序的运行结果取决于Address类是否重写了equals方法。
如果没有重写,默认equals是比较地址,那么这两个address对象不一样,输出2,意味着hibernate会认为这是两个对象,再接下来的持久化过程中可能会出错。
如果重写了equals,比如按照主键(address空间地址)比较,那么这两个对象是一样的,输出1 。