一、hibernate与 db中数据类型对照(xml方式)
1.与ORACLE常用数据类型对照
背景为灰色的表示常用,熟记。
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) |
<hibernate-mapping> <class name="com.besttone.domain.OrderHead" table="ORDER_HEAD"> <id name="orderHeadId" type="java.lang.Long"> <!-- <generator class="sequence"> <param name="sequence">ORDER_HEAD_SEQ</param> </generator> --> <column name="ORDER_HEAD_ID" precision="22" scale="0"/> <generator class="sequence" /> </id> <property name="userId" type="java.lang.String"> <column length="60" name="USER_ID"/> </property> <property name="productId" type="java.lang.Long"> <column name="PRODUCT_ID" precision="22" scale="0"/> </property> <property name="payTotal" type="java.lang.Double"> <column name="PAY_TOTAL" precision="22" scale="0" /> </property> <property name="createdDate" type="java.sql.Timestamp"> <column length="11" name="CREATED_DATE"/> </property> </class> </hibernate-mapping> |
2.与MySql数据类型对照
背景为灰色的表示常用,熟记。
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 |
二、Hibernate 关系配置
1.annotation基本类型配置
配置、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) 两者兼具
2. annotation 列属性映射
使用 @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;
}
3.联合主键:
必须实现 po层Serializable接口
<classname="Student" table="t_student">
<composite-idname="studentId" class="StudentId">
<key-propertyname="firstName" length="20"></key-property>
<key-propertyname="lastName" length="20"></key-property>
</composite-id>
<propertyname="pwd" length="20"></property>
</class>
4. 组合关系
<class name="User" table="t_user" >
<id name="id">
<generatorclass="native"></generator>
</id>
<propertyname="name"></property>
<property name="phone"column="dianhua" length="30"></property>
<componentname="address" class="Address" >
<propertyname="city"></property>
<propertyname="street"></property>
<propertyname="zipcode"></property>
</component>
</class>
5. 一对多,多对一
5.1 xml格式的:
一方:
<classname="Department" table="t_dept">
<idname="id" >
<generatorclass="native"></generator>
</id>
<propertyname="dname" length="20"></property>
<setname="employees" >
<key>
<columnname="department_id"></column>
</key>
<one-to-many class="Employee"/>
</set>
</class>
多方:
<classname="Employee" table="t_emp">
<idname="id">
<generatorclass="native"></generator>
</id>
<propertyname="ename"></property>
<many-to-onename="department" class="Department"column="department_id">
</many-to-one>
</class>
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<Money> moneys;
6. 一对一 外键关联
6.1 xml格式的:
<classname="Address" table="t_address" >
<idname="id">
<generatorclass="native"></generator>
</id>
<propertyname="aname" length="20"></property>
<one-to-one name="company"class="Company"property-ref="address"></one-to-one>
</class>
<classname="Company" table="t_com" >外键生成
<idname="id">
<generatorclass="native"></generator>
</id>
<propertyname="cname" length="20"></property>
<many-to-one name="address"class="Address" cascade="save-update">
<column name="address_id"unique="true"></column>
</many-to-one>
</class>
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. 多对多
7.1 xml格式的:
xml格式的:
<classname="Course" table="t_course">
<idname="id" >
<generatorclass="native"></generator>
</id>
<propertyname="cname" length="20"></property>
<setname="students" table="student_course">
<key>
<columnname="course_id"></column>
</key>
<many-to-manyclass="Student" column="student_id"></many-to-many>
</set>
</class>
<classname="Student" table="t_student">
<idname="id" >
<generatorclass="native"></generator>
</id>
<propertyname="sname" length="20"></property>
<setname="courses" table="student_course">
<key>
<columnname="student_id"></column>
</key>
<many-to-manyclass="Course" column="course_id"></many-to-many>
</set>
</class>
7.2 annotation格式的:
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privateInteger id;
privateString mname;
@ManyToMany(mappedBy="moneys")
privateSet<Student> students;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privateInteger id;
privateString sname;
privateString pwd;
@ManyToMany
privateSet<Course> moneys;
8. 其他
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
<class name="Teacher"table="Teacher" >
<id name="id"column="id"></id>
propertyname="name" type="time" />
</class>
三、hibernate序列Sequence
<id name="id" >
<generatorclass="native"></generator>
</id>
其他常用的序列生成方式
1. <generator class="sequence"/>
这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当然,Hibernate提供了很多内置的实现。下面是一些内置生成器的快捷名字:
2. increment(递增)
用于为long, short或者int类型生成唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。(补充:主键按数值顺序递增,此方式的实现机制为在当前实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候在此值上加1作为主键,可能产生的问题:如果当前有多个实例访问同一个数据库,那么由于各个实例都维持主键状态,不同实例可呢生成同样主键,从而造成主键重复异常,因此,如果同一个数据库有多个实例访问,此方式必须避免使用。)
3. sequence(序列)
在DB2,PostgreSQL,Oracle, SAP DB, McKoi中使用序列(sequence),而在Interbase中使用生成器(generator)。返回的标识符是long, short或者 int类型的。
4. uuid.hex
用一个128-bit的UUID算法生成字符串类型的标识符。在一个网络中唯一(使用了IP地址)。UUID被编码为一个32位16进制数字的字符串。
5. native(本地)
根据底层数据库的能力选择identity, sequence 或者hilo中的一个。(详解:由hibernate根据数据库适配器中的定义,自动采用identify、hilo、sequence的其中一种作为主键生成方式)
6. id的annotation方式
@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;
}
四、hibernate 配置
1.日志配置
a) slf4j与log4j的关系:slf4j像是一个大管家,可以管理许多的日志框架,log4j是其中之一
b) 加入slf4j-log4j.jar,加入 log4j 的 jar 包,去掉 slf4-nop.jar
c) 从hibernate/project/etc目录 copy log4j.properties
2. hibernate.cfg.xml配置文件
<!--显示输出sql-->
show_sql
<!--格式化显示输出sql -->
<propertyname="format_sql">true</property>
五、hibernate 联合主键
1. xml方式: composite-id
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配置方法
<hibernate-mapping>
<classname="com.bjsxt.pojo.Student" >
<composite-idname="studentPK" class="com.bjsxt.pojo.StudentPK">
<key-propertyname="id"></key-property>
<key-propertyname="name"></key-property>
</composite-id>
<propertyname="age" />
<propertyname="sex" />
<propertyname="good" type="yes_no"></property>
</class>
</hibernate-mapping>
2. Annotation方式
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;
}
六、hibernate 核心开发
1. Configuration
a) AnnotationConfiguration
b) 进行配置信息的管理
c) 用来产生SessionFactory
d) 可以在configure方法中指定hibernate配置文件
e) 只气关注一个方法即:buildSessionFactory
2. SessoinFactor
1) 用来产生和管理Session
2) 通常情况下每个应用只需要一个SessionFactory
3) 除非要访间多个数据库的情况
4) 关注两个方法即:openSession getCurrentsession
i. open session每次都是新的,需要close
ii. getCurrentsession从上下文找,如果有,用旧的,如果没有,建新的
1. 用途,界定事务边界
2. 事务提交自动close
3. 上下文配置可参见xml文件中
<property name="current_session_context_classs">thread</property>
4. current_session_context_class (jta、thread常用 managed、custom.Class少用)
a) thread 使用connection 但数据库连接管理事务
b)jta (全称java transaction api)-java分布式事务管理(多数据库访问)
jta由中间件提供(jboss WebLogic等,tomcat不支持)
3.Session
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)
七、hibernate 对象的三种状态
1. 三种状态的区分关键在于
i. 有没有ID
ii. ID在数据库中有没有
iii. 在内存中有没有(session缓存)
2. 三种状态:
a) transient:内存中一个对象,没ID,缓存中也没有
b) persistent:内存中有,缓存中有,数据库有(ID)
c) detached:内存有,缓存没有,数据库有,ID
八、hibernate id特殊配置
1. 组合关系
<class name="User" table="t_user" >
<id name="id">
<generatorclass="native"></generator>
</id>
<propertyname="name"></property>
<propertyname="phone" column="dianhua" length="30"></property>
<componentname="address" class="Address" >
<propertyname="city"></property>
<propertyname="street"></property>
<propertyname="zipcode"></property>
</component>
</class>
2.
九、hibernate 注意事项
1. 在Hibernate中,POJO类要重写hashcode()方法和equals()方法。
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。