1 对应项目:hibernate_0400_ID
2 注意:
a) 我们观察hibernate生成表的结构并不是为了将来就用它生成,(可能还有自己的扩展,比如index等)而是为了明白我们应该建立什么样的表和实体类映射
3 xml生成id
a) generator
<idname="id" >
<generator class="native"></generator>
</id>
b) 常用四个:nativeidentity sequence uuid
4 注解方式:@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 int getId() {
returnid;
}
e) TABLE (可以忘记)
i. @TableGenerator
@TableGenerator(name="teacherID",
table="teacherID_DB",
pkColumnName="key_value",
pkColumnValue="pk_value",
valueColumnName="teacher",
allocationSize=1)
注:如果使用注解方式的uuid 如下:
@Id
@GeneratedValue(generator="teacherUUID")
@GenericGenerator(name="teacherUUID",strategy="uuid")
5 FAQ;
a) 用Junit测试时Hibernate Session Factory初始化异常不提示.疑似一个bug
b) 用main来做测试
6 联合主键
a) Xml方式: composite-id
i. 将联合主键的属性提取出来,重新编写一个pojo类(原pojo类中的id,name要删除 并新加入属性“StudentPK”)
publicclass StudentPK implements Serializable {
private String id;
private String name;
… …
ii. 新建pojo类必须实现 java.io.Serializable 序列化接口
iii. 新pojo类要重写equals和hashCode方法
@Override
public boolean equals(Objecto) {
if(o instanceof StudentPk) {
StudentPk pk = (StudentPk)o;
if(this.id == pk.getId() &&this.name.equals(pk.getName())) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return this.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>
b) Annotation
i. 前三步与Xml方式前三步一样都要建立新pojo类 都要实现Serializable接口 重写equals和hashCode方法.
ii. 方法1在新类前写@Embeddable,在原pojo类的新属性“TercherPK”的get方法前写@ld,如下
@ Embeddable
publicclass TeacherPK implements Serializable {
private String id;
private String 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;
}
... ...
1 hibernate_0500_CoreAPI
2 Hibernate API文档需要单独下载
3 Configuration
a) AnnotationConfiguration
b) 进行配置信息的管理
c) 用来产生SessionFactory
d) 可以在configure方法中指定hibernate配置文件
e) 只气关注一个方法即:buildSessionFactory
4 SessoinFactor
a) 用来产生和管理Session
b) 通常情况下每个应用只需要一个SessionFactory
c) 除非要访间多个数据库的情况
d) 关注两个方法即:openSession getCurrentsession
i. opensession每次都是新的,需要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由中间件提供(jbossWebLogic等,tomcat不支持)
5 Session
a) 管理一个数据库的任务单元(简单说就是增 删 改 查)
b) 方法(CRUD)
i. Save()
ii. delete
iii. load
iv. get
v. get与load的区别
1. 不存在对应记录时表现不一样
2. load返回的是代理对象,等到真正用到对象的内容时才发出sql语句
3. get直接从数据库加载,不会延迟
vi. 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.0Annotation 没有对应的属性,hibernate 扩
展?
i. 同一个session可以,跨session不行,不过可以用merge()(不重要)
c) 使用 HQL(EjBQL)(建议)
vii. saveOrUpdate()
viii. clear方法
1.无论是load还是get,都会首先査找缓存(一级缓存),如果没有,才会去数据库査找,调用
clear()方法可以强制清除session缓存
ix. flush()方法
1. 当session的事务提交后,会强制将内存(session缓存)与数据库同步.默认情况下是session的事务提交(commit)时才同步!
2. session的FlushMode设置,可以设定在什么时候同步缓存与数据库(很少用)
例如: session.setFlushMode(FlushMode.AUTO)
x. find方法已经过时!
6 SchemaExport (自动建表)
7 Query 接口
a) 参考Hibernate査询(HQLEJBQL)的内容
8 Note:
a) Hibernate中涉及很多非常非常细节的区别,但在实际应用中用得极少,请大家先享受写项目的乐
趣,再来探讨这些细节问题
i. 比如save和persist的区别
ii. merge、evict 等方法
iii. 比如 refresh、lock 等
b) 建议的学习方法,动手实验
c) 细节问题参考补充视频
1 上一个 project
2 三种状态的区分关键在于
a) 有没有ID
b) ID在数据库中有没有
c) 在内存中有没有(session缓存)
3 三种状态:
a) transient:内存中一个对象,没ID,缓存中也没有
b) persistent:内存中有,缓存中有,数据库有(ID)
c) detached:内存有,缓存没有,数据库有,ID
4 对这三种状态需要关注的问题是在该状态下如果进行数据库的操作会发生什么结果,比 如改变属性的
值会不会发出update语句?
a) 强烈建议动手实验
b) 进行正常人的思考
c) 绝对不要去背这些东西!背过也并不代表你有多牛!
1 这里的关系映射指的是对象之间的关系,并不是指数据库的关系,本章解决的问题是当对象之间处于
下列关系之一时,数据库表该如何映射,编程上该如何对待(红色为重点)
2 简化问题:
a) 怎么写 Annotation
b) 增删改査CRUD怎么写
3 —对一
a) 单向(主键、外键)
b) 双向(主键、外键)
c) 中间表
4 —对多
a) 一张主表,多张子表
5 组件映射
a) @Embeddable
b) @ Embedded
1 一对一单向外键关联
a) 项目名称:hibernate_0600_one2one_uni_fk
b) Annotation: 在被约束表字段的get方法上加@0ne20ne @JoinColumn
@OneToOne
@JoinColumn(name="wifeid")//指定生成的数据库字段名
publicWife getWife() {
return wife;
}
c) xml: 在被约束表的xml配置文件中加<many-to-one unique
<classname="com.bjsxt.pojo.StuIdCard">
<id name="id">
<generatorclass="native"></generator>
</id>
<propertyname="num"/>
<many-to-onename="student" column="studentId"unique="true">
</many-to-one>
</class>
unique="true"是保证生成的字段唯一,这样<many-to-one 也达到了一对一的效果
021 例子程序
021 oracle里面表名不能前面有 _
021 用native自己根据数据库选择id生成方式 (跨平台方便)
021 标签的写法
默认的value 是auto increasment 相当于xml里面的native
JPA属于J2EE 有专门的文档
Identity—用于SQLServer MySQL 自增
Sequence- 用于oracle
这种标签指定的sequence 所有的表格共用一个而且名字由hibernate自动生成
指定各表用不同的sequence的方法可以指定每个生成器的名称
先声明sequence生成器再类上面
在这边指定要刚刚声明的那个sequence
023 Table法 用一个表格生成sequence
文档里面的例子generator
先声明一个TableGenerator 表生成器
在get之前指定使用刚刚声明的东西
用一张名叫generator_Table的表存所有目前的sequence的最大值+1 ,
key(varchar)相当于名字 value(integer)相当于当前最大的sequence值 最开始的时候 value=1 这张表可以提供无限多个key因为一条记录就保存了一个sequence
当使用时从中读取对应表的value值,并且把这个值作为当前记录的id
用完之后 +1 存回去
当hibernate 生成的sql语句出错的时候我们可以去数据库里面尝试运行这个sql语句这样方便调试
在mySQL里面key是关键词所以不能作为列名
跨数据库平台的时候使用这种方式最好. 用Native不能相互移植数据(但是毕竟很少用了解)
总结
024 联合主键
要定义一个主键类
要实现serializable 序列化接口方便把数据放到虚拟内存里
StudentPK类需要重写equals和hashcode方法 保证这个联合主键不重复
Equals告诉系统怎么区分两个主键对象是否相同 :要两个id都相同才行
Hashcode 因为从hash表中查找student对象时, 根据student主键来查找student对象的存放位置 这个位置是根据主键来获得的 所以我们要在主键类里重写hashcode(传到其他机子上 或者传到硬盘的时候需要序列化)
在model中用一个主键对象来确定每个model 作为这个model的id
为主键对象赋值的时候
xml配置方法 以上都是XML联合主键的使用方法
025 用annotation的方法来设计联合主键
1)
2)常用
一句话就可以
3) 第三种方法 比较常用
主键类里面不用添加任何东西
类前要添加这一行来指定联合主键类是哪个
这种方式存数据的时候还是用setID setName
但是取数据的时候要用到主键对象(所以主键类还是有存在的必要取的时候要用)
总结
后两种常用
搞明白这两个问题
026 hibernate核心
可以在configure()中指定配置文件的名称
可以理解为维护数据库连接池用来产生session(理解为连接)
Session中绑定了一个连接 所以可以理解为一个connection
OpenSession永远打开新的sessiongetCurrentSession先查找目前有的Session有就用没有菜开一个新的
前者用完之后要.close
这样后一个会直接获取当前已经有的session 因此打印出的结果是true
当前面的session提交之后再拿 就是新的session
在提交之前无论那多少次 都是拿原来的
应该一个Service方法作为一个事务这样里面的每一个单独的行为应该采用getcurrentSession 这样才能组合起一个事务
CurrentSession的上下文的范围
Thread 线程范围(主要和事务相关)managed自己管理(极少) custom.class(自己写类管理)
分布式事务由JTA实现加入要把跨越两个不同数据库的操作放在同一个事务里面
(面试 重要)
Tomcat不支持这种服务 所以我们不能在现有的项目里面使用JTA事务管理的方法
028
openSession和getCurrentSession 两种方法不能混用 一次只能用一个方法
Hibernate的API
老师给的API
Transient 对象刚new出来的时候 还没有和数据库连上
Persistent 对象和数据库connection做链接 连接上了 这时候对象作出的一些变化会原样记录到数据库里
Detached 对象脱离数据库的链接
1 Transient 刚new出来 没id 缓存里没有 数据库里也没有
2 Persistent save了 内存里有 缓存里有 数据库里有 (ID有了)
3 Detached 数据库里有 缓存和内存里没有 这时候session已经不在了 对象里(ID有)
Delete()
对象一定要有id号才可以删 2 3 状态都可以删只要有ID号
一个对象只有id 其他属性都没有 也可以delete()
Load()
从数据库里取一个对象出来给你
第一个参数取出来的对象类型 class 第二个是id
拿回来之后是object 要强制类型转换
Load返回的是一个代理 并没有真正把一个对象取出来 没有发出sql语句
直到你真的使用这个对象中的值得时候才会发出sql语句
代理对象名
Get方法
真真实实拿一个对象给你
032 update()
可以更新一个detached对象
Update一个有id的对象
所以update能用在2 3 类型的对象上以及你设定好id的1型对象
2状态的对象 你更新某个属性 数据库就同步更新
Session在提交或者关闭的时候 会检查persistent的对象的内容和缓存中不一致 就会帮你更新到两者一致
更新部分字段
A)
这种方法不好不灵活
B)
Dynamic-update的效果是 在同一个session里面 只更新改过的字段
更新detached对象的时候,这样设置还是会更新全部字段因为他没有缓存中的东西可以做比较无法判断有哪些字段做了变化(实际上用不到可以忘掉)
Merge()方法,在没得查内存的情况下会先去数据库查原来的对象和你要更新的那个对象做对比然后再决定更新哪个.
C) 用HQL EJBQL语句
自己写hql语句运行 hql 一种面向对象的查询语言
一般情况下, 如果能接受效率不一定要做部分字段更新
033 saveOrUpdate()
取决于对象的属性值来决定到底是save还是update
前面没有id 执行save 后面有id 执行update
033 clear()
从缓存判断id为1的teacher已经存在所以load语句第二次没有发sql语句直接从缓存拿teacher
这样加了clear()就清除了session缓存这样会发两条sql语句
033 flush()
因为update只有在commit的时候发出所以这样只有一条sql语句执行
当两条setName语句之间加上session.flush()的时候就会强制缓存中的对象和数据库中的一致
Clear和flush的区别
clear清除是直接把对象清除掉 现有的对象编程1 状态 和session脱离了关系
flush则不会改变对象性质 2型对象还是2型
在commit的时候默认会进行flush
可以我们自己设定flush的类型 flushMode 要在session刚开始的时候设
这些在调节性能的时候会用到(极小机会用到)
034 用SchemaExport建表
后面两个true 第一个表示是否显示ddl语句后一个true表示是否真正执行这些ddl语句
当我们需要先建类通过类生成建表语句的话我们可以用这个来调试
035 整理方法和属性的顺序
035
一对一外键关系
Crtl+C+向下 拷贝整行
移动的话不按C
这是这种一对一生成的表
在powerdisigner中先连数据库用odbc优先如果没有 用jdbc
反向工程 由表生成视图(看别人数据库的时候方便)
必须把这个jar文件里面设到classpath变量里面
OneToOne里面有这些属性
可以指定生成的外键的名称