首页 > 代码库 > Hibernate零散笔记
Hibernate零散笔记
可以建立自己的user Library。(第二集)
加入mysql的驱动mysql-connector
在数据库中建立相应的内容:
create database hibernate;
use hibernate;
create table student(id int primary key, name varchar(20),age int);
建立student类:
建立hibernate配置文件,hibernate.cfg.xml:
<?xml version=‘1.0‘ encoding=‘utf-8‘?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings (hibernate自动帮你链接了数据库,填入相关信息) -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernate</property>
<property name="connection.username">root</property>
<property name="connection.password">abc123</property>
<!-- JDBC connection pool (use the built-in) (hibernate的连接池) -->
<!-- <property name="connection.pool_size">1</property> -->
<!-- SQL dialect (hibernate方言,hibernate统一了sql语言,将统一语言翻译成下面填写的相应的数据库语言) -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate‘s automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache (将二级缓存disable掉) -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout (将生成的sql语句打印出来) -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup (是否让hibernate自动生成ddl(建表语句)) -->
<!-- <property name="hbm2ddl.auto">update</property> -->
<mapping resource="com/bjsxt/hibernate/model/Student.hbm.xml"/>
</session-factory>
</hibernate-configuration>
还要指明object与表字段的对应关系。建立映射文件,Studnet.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.hibernate.model">
<class name="Student"> //找到对应的类
<id name="id" column="id" /> //id表示为主键
<property name="name" /> //property表示一般字段
<property name="age" />
</class>
</hibernate-mapping>
写测试类:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.bjsxt.hibernate.model.Student;
public class StudentTest {
public static void main(String args[]){
Student s = new Student();
s.setId(1);
s.setName("s1");
s.setAge(1);
Configuration cfg = new Configuration();
SessionFactory sf = cfg.configure().buildSessionFactory(); //SessionFactory产生connecyion的工厂
Session session = sf.openSession();
session.beginTransaction();
session.save(s); //将对象s插入数据库
session.getTransaction().commit();
session.close();
sf.close();
}
}
annotation(利用annotation注解就可以不用*.hbm.xml文件):
建立新表:
create table teacher (id int primary key,name varchar(10),title varchar(20));
建立对象Teacher并加入注解annotation:
package com.bjsxt.hibernate.model;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity //表示实体类,对应于数据库表中的一个表
public class Teacher { //利用annotation注解就可以不用*.hbm.xml文件
private int id;
private String name;
private String title;
@Id //表示主键
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
JDBC操作数据库很繁琐
sql语句是面向关系而不是面向对象
可以再对象和关系表之间建立关系来简化变成
o/r mapping跨越数据库平台
表名与类名不同的时候,对表名进行配置
Annotation:@Table
xml:...
字段名与属性相同的时候:默认为@Basic;xml中不写column
字段名与属性名不同的时候:
Annotation:@Column
xml:...
不需要psersitence(持久化,存入数据库)的字段:
Annotation:@Transient
xml:直接不写
映射日期与时间类型,指定时间精度:
Annotation:@Temporal
xml:制定property标签的type属性
枚举类型的映射:
Annotation:@Enumerated
xml:...
注解的位置:
可以放在field(成员变量)上面,
也可以放在getxxx方法上面。
Junit4有BUG:第19个视频
ID生成策略:对应项目hibernate_0400_ID
注意:
我们观察hibernate生成表的结构并不是为了将来就用他生成(也可能还有自己的扩展,比如index),而是为了明白我们应该尽力什么样的表和实体类映射。
xml生成id:
使用generator
常用的有四个:native identity sequence uuid
annotation生成id:
@GeneratedValue
有四种取值方式:auto identity sequence(@SequenseGenrator) table(@TableGenerator)
联合主键:
xml:composite-id(要实现serializable和重写equals和hashcode)
annotation:
将类注解为@IdClass,并将该类实体中的所有属于主键的属性都注解为@Id
将组件类注解为@Embeddable.并将组件的属性注解为@Id
将组建的属性注解为@Embeddable
Hibernate的核心开发接口:
sessionFactory有两个方法得到Session:
1.openSession:每次都打开一个新的Session,用完要关闭
2.getCurrentSession:拿到当前上下文(可以在配置文件中设置current-context-class,主要有jta和thread)已有的Session或者打开一个新的Session(前一个Session被commit之后),用完不用关闭,commit()之后自动关闭。
Session是个接口,这两种方法得到的具体类可能不一样,所以不能混用
两种方法的区别很重要
区别在第26集。
JPA界定事物边界,例如数据存入和日志记录需要在同一个事物之内完成。
还有一种事物JTA,分布式数据库。
对象的三种状态:
怎么区分:
1.对象有没有ID
2.ID在数据库中有没有
3.在内存(session缓存)中有没有ID
1.transient:内存中一个对象,没ID,缓存中也没有ID
2.persistent:内存中有ID,缓存中有ID,数据库有ID
3.detached:内存有ID,缓存没有ID,数据库有ID
delete方法:
只要有ID就可以调用delete方法
get和load的区别:
get会马上执行sql语句得到对象
load会生成并返回一个代理对象,直到你取该对象的属性,这个代理才会执行sql语句得到对象
不存在对应记录的时候有区别。
update:
用来跟新detached对象,更新完成后可以转化为persistent状态
更新transient会报错
跟新自己设定ID的transient对象可以(前提是数据库有对应记录)
当一个persistent对象的字段被改变的时候,commit会检查修改,且更改全部字段。
下面的方法只让他修改相应的修改了的字段:第32个视频。
clear:
无论是load还是get,都会先查找缓存,如果没有,才会去数据库查找,调用用clear方法可以强制清除Session缓冲。
flush:
可以强制进行从内存到数据库的同步,commit时就执行一次flush。
关系映射:
对象之间的关系:
一对一:
单向:
每个Husband对应一个Wife,Wife中没有对应的Husbus,则此为单向关联
在数据库有中用外键关联
@OneToOne @JoinColumn(name="wifeId")
双向:
每个Husband对应一个Wife,Wife中也对应一个Husbus,则此为双向关联
@OneToOne(mappedBy)
联合主键:
@JoinColums
一对多(多对一):
设局库表设计:在多的一方加外键。
多对多:
单向关联:
老师和学生的关系,老师需要知道自己教了哪些学生。
双向关联:
老师知道自己教了哪些学生,学生也知道教自己的有哪些老师。
此外还可以根据单向还是双向可以非为7种。
Ctrl+Alt+下 复制这一行到下一行
Alt+下 移动这一行到下一行
powerdesigner可以用于分析代码,生成表的关系图。
关联关系中的CRUD:
设定cascade可以设定在持久化时对于对象的操作。
C--create
R--retrieve(取出load get)
U--update
D--delete
Cascade属性致命做什么操作的时候关联对象是绑在一起的
Merge=save+update
refresh=A里面需要读B改过之后的数据
铁律:双向关系在程序中要设定双向关系,双向关系设定mappedBy(在一的那一方设置)
fetch:
双向不要两边设置Eager(会有多余的查询语句发出)
对多的乙方设置fetch的时候要谨慎,结合具体情况,一帮使用Lazy不使用eager(特别情况:多方的数量不是很多的时候可以考虑,提高效率的时候可以考虑)。
O/RMapping编程模型:
1.映射模型
jap annotation
hibernate annotation extension
hibernate xml
jap xml
2.编程接口
jap
hibernate
3.数据查询:
hql
ejbql(jpql)
要删除或者更新的时候,先load,除了精确知道ID号之外。
如果要消除关联关系,先设定为NULL,在删除记录,如果不删除记录,该记录就会变成垃圾数据。第51集。
如果指定@OneToOne的属性fetch为FetchType.LAZY,会延迟对于关联对象的加载,不论使用的是load还是get。
关系映射总结:什么样的关系,设计什么样的表,进行什么样的映射。
继承映射:
1.一张表single_table
2.每个类分别一张表table_pre_class
3.每个子类一张表joined
树状结构的设计(至关重要):
在用一个类中使用one2many和many2one。
Hibernate查询(query language)
HQL&EJBQL
1.NativeSQL
2.HQL(Hibernate ql)
3.EJBql(JPql 1.0)--可认为是hql的子集
4.qbc
5.qbe
性能优化:
注意session.clear()的使用,尤其在不断分页循环的时候,否则会造成内存泄漏。
JAVA有内存泄露吗?
在语法级别上没有,但是在实际上可能会间接造成,如果他调用用了C,在调用OS,而C需要手动控制内存。
1+N问题(很重要):
第64集
解决方案:
1.设置LAZY
2.BatchSize
3.join fetch
用得最多的是1 3。
list和Iterate的区别:
1.list取所有
2.iterate先去ID,等用到的时候再根据ID来去对象
3.session中list第二次发出,仍会到数据库查询
4.iterate第二次发出,则会先找session缓存
hiberbate中有三种缓存:
1.一级缓存(Session级)
2.二级缓存(SessionFactory级)
可以跨Session存在
以下情况使用二级缓存:
1.经常被访问
2.不会经常改动
3.数量有限
如:用户权限、组织机构
hibernate.cfg.xml设定:
<property name="cache.use_second_level_cache">true</property> //打开二级缓存
<property name="cache.provider_class">org.hibernate.cache.EnCacheProvider</property> //指明使用哪种二级缓存
添加注解:
@Cache
load默认使用二级缓存,iterate默认使用二级缓存
list默认往二级缓存加数据,但是查询的时候默认不使用
3.查询缓存
只有在查询语句完全一样才有效。查询缓存依赖于二级缓存,所以必须同时打开二级缓存。
调用Query的setCachable(true)方法指明使用二级缓存。
缓存算法:(当缓存满了之后怎么办)
1.LRU:Least Recently Used(最近最少被使用的被清除)
2.LFU:Least Frequently Used(使用频率最少的被清除)
3.FIFO:First In First Out(先来的先被清除)
可以在ehcache中设置使用哪一种:
memoryStoreEvictionPolicy="LRU"
事物并发处理:
事物的特性:ACID
Atomic(原子性) Consistency(独立性) Itegrity(一致性) Durability(持久性)
事物经常出现的问题:
脏读 不可重复读 幻读
数据库的事物的隔离机制:
1:read-uncommitted
2:read-committed
4:repeatable read
8:serilizable
只要数据库支持事物,就不可能出现第一类丢失跟新。
read-uncommitted会出现dirty read,phanton-read,non repeatable read问题。
read-committed不会出现dirty read,因为只有另一个事物提交才会读出来结果,但仍然会出现phanton-read,non repeatable read.
repeatable read。
serial解决一切问题。
设定hibernate的事物隔离级别:
一般设定hibernate.connection.isolation=2 //考虑效率
用悲观素解决repeatable read的问题(依赖于数据库的锁)