Hibernate学习笔记
OJB,JDO,TOPLINK,EJB(CMP),JPA,IBATIS,
JNDI
英文全称:Java Naming and Directory Interfaces
术语解释:一组帮助做多个命名和目录服务接口的API。
ORM框架使用范围:
针对某个对象进行操作时适用
ORM框架都不适合对象批量操作
实体之间有清晰的映射关系时适用(映射:数据和字段对应明确)
Hibernate的搭建
HIBERNATE.CFG.XML
FORMAT 格式化SQL语句
XML配置文件
- 1. jar包的引入
- 2. 创建一个hibernate.cfg.xml,然后修改数据库连接
<!-- MySql -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/Student</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Oracle -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:ORCL</property>
<property name="connection.username">scott</property>
<property name="connection.password">tiger</property>
<property name="dialect">org.hibernate.dialect.OracleDialect</property>
com.mysql.jdbc.Driver
jdbc:mysql://local:3306/hibernate
- 3. 创建实体类
- 4. 创建实体类的映射文件
Hibernate Annotation 注解
- 1. 需要的jar包
- 2. 实体+映射@Entity @Table+@ID //主键
- 3. Hibernate.cfg.xml:
<mapping class=”com.test.hibernate.model.User”>
Configuration cfg = new AnnotationConfiguration();
4. ID生成策略
1)Annotation
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name = "_name")
private String name;
private String title;
// @Temporal(TemporalType.DATE) //日期
// @Temporal(TemporalType.TIME) //时间
@Temporal(TemporalType.TIMESTAMP)//时间日期
private Date birth;
@Transient //不需要再数据库中生成的字段
private String yourhusband;
@Enumerated(EnumType.STRING)
private Sex sex;
@Enumerated(EnumType.ORDINAL)
private Sex sex2;
2)XML
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
3)Oracle Sequence Generator
@Entity
@Table(name = "T_teacher")
@SequenceGenerator(name="teacherSeq",sequenceName="T_S_DB")
public class Teacher {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="teacherSeq")
private int id;
@Column(name = "name")
private String name;
private String title;
// @Temporal(TemporalType.DATE) //日期
// @Temporal(TemporalType.TIME) //时间
@Temporal(TemporalType.TIMESTAMP)//时间日期
private Date birth;
@Transient //不需要再数据库中生成的字段
private String yourhusband;
@Enumerated(EnumType.STRING)
private Sex sex;
@Enumerated(EnumType.ORDINAL)
private Sex sex2;
Hibernate Log
- 1. 属性文件log4j.xml
内容:
log4j.rootLogger=WARN, Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=(%r ms) [%t] %-5p: %c#%M %x: %m%n
log4j.logger.com.genuitec.eclipse.sqlexplorer=DEBUG
log4j.logger.org.apache=WARN
log4j.logger.org.hibernate=WARN
- 2. Jar包
Hibernate 常用接口
Configuration cfg = new AnnotationConfiguration().config();
SessionFactory sf = cfg.buildSessionFactory();
Session s = sf.openSession(); //每次都创建一个新的Session,需要有close()
Session s = sf.getCurrentSession(); //从 上下文中获取当前的Session
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
Thread:适用于单数据库操作(单一事务)
Jta:适用于多个数据库的操作(分布式事务)Java Transaction API
依赖于应用服务器
(web服务器是应用服务器中的一种)
Hibernate三种状态
Transient:刚new出来的时候,不存在id;
Persistent:save()/saveOrUpdate()之后,内存和数据库中都存在id;
Detached:close()之后,缓存中不存在id,只有数据库中存在id.
Hibernate 常用方法
- 1. 插入数据的方法
Save()
- 2. 删除数据的方法
Delete()
3.查询数据的方法
Lode() //在调用Session对象的时候才执行此方法
Get() //执行到此行时即立即执行sql语句
Find() //查询方法但是很少遇到
- 4. 修改语句
Update()
如果一个对象是persistent状态,那么在调用setXX()方法后Session会自动检测内存中的数据和数据库中的数据是否一致,如果不一致则会自动修改,并发出sql语句,但是update()方法会更新整条数据,如果只想更新单条数据中的某个字段,可以使用HQL语句。
其他防止更新多余字段的方法:
1) Annotation中@Column的updatable属性设置为false;xml文件中可以设置update属性
2) Xml文件中,在table中设置dynamic-update
3) 如果不是在同一个session中可以使用merge()方法。
SaveOrUpdate();
- 5. Clear():用于清除内存;
- 6. Flush():用于统一内存和数据库之间的数据是否统一
Session.setflushMode(FlushMode.XXX); //用于设置是否flush
- 7. SchemaExport(new AnnotationConfigration().configrat()).create(true,true);//默认生成建表语句
Hibernate对象之间的关联
1. 一对一单向外键关联
Annotation中的配置:
@OneToOne //设置对象之间一对一的关系
@JoinColumn(name="idCard") //设置对象所关联的列的名称
XML文件中的配置:
<many-to-one name="Student" column="studentId" unique="true">
</many-to-one>
- 2. 一对一双向外键关联
@OneToOne(mappedBy=”student”)
<one-to-one name=”Student” column=”StudentId” property-ref=”Student”></one-to-one>
- Cascade存取
- Fetch 读取
Hibernate乐观锁和悲观锁
在使用Hibernate的过程我们会遇到多个人对同一数据同时进行修改,这个时候就会发生脏数据,造成数据的不一致性。为了避免更新数据的丢失,Hibernate采用锁机制。
Hibernate提供了两种锁机制:悲观锁和乐观锁。 悲观锁:在数据有加载的时候就给其进行加锁,直到该锁被释放掉,其他用户才可以进行修改。 乐观锁:在对数据进行修改的时候,对数据采用版本号或者时间戳等方式来比较,数据是否一致性来实现加锁。
一、悲观锁 悲观锁是依靠数据库提供的锁机制。Hibernate是通过使用数据库的for update子句实现了悲观锁机制。
Hibernate有如下五种加锁机制 1、 LockMode.NONE:无锁机制 2、LockMode.WRITE:Hibernate在Insert和Update记录的时候会自动获取 3、LockMode.READ:Hibernate在读取记录的时候会自动获取 4、LockMode.UPGRADE:利用数据库的for update子句加锁 5、LockMode.UPGRADE_NOWAIT:Oracle的特定实现,利用Oracle的for update nowait子句实现加锁
悲观加锁一般通过以下三种方法实现: 1、Criteria.setLockMode 2、Query.setLockMode 3、Session.lock 下面示例是对查询进行加锁: [java]
public void query(int id){ Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction(); String hql = "from Users as u where id= :id"; List list = session.createQuery(hql) .setLockMode("u", LockMode.UPGRADE) //执行加锁 .setInteger("id", id)
.list(); for(Iterator iterator = list.iterator();iterator.hasNext();){
Users users = (Users) iterator.next();
System.out.println(users.getBirthday()); } }
产生的SQL语句如下: [sql] select users0_.id as id0_, users0_.ver as ver0_,
users0_.birthday as birthday0_, users0_.first_name as first4_0_, users0_.last_name as last5_0_ from Users users0_
with (updlock, rowlock) where users0_.id=?
悲观锁在对数据进行加锁后,会一直“霸占”该数据,直到释放掉,其他用户才可以对该数据进行更新。这里就存在一个问题,如果它一直占着不放,那么其他用户永远也不可能对该数据进行更新,这样就很不利于并发了。对于这个问题的解决方案,可以利用乐观锁。
二、乐观锁 乐观锁大多是基于数据版本记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
我们可以通过class描述符的optimistic-lock属性结合version描述符指定乐观锁。 1. none:无乐观锁 2. version:通过版本机制实现乐观锁 3. dirty:通过检查发生变动过的属性实现乐观锁 4. all:通过检查所有属性实现乐观锁 在实现乐观锁的持久化类我们需要为该持久化类增加一个version属性,并且提供相应的getter和setter方法。如下 [java] public class Users { private int id; private Date birthday; private Name name;
private int version;
//舍掉getter和setter方法 }
配置文件: [html] < hibernate-mapping package="com.hibernate.domain"> <class name="Users" optimistic-lock="version"> <id name="id"> <generator class="native" /> </id> <version name="version" />
<property name="birthday" />
<!-- 映射组件元素 --> <component name="name"> <!-- 映射组件的name属性指向包含实体 -->
<property name="firstName" column="first_name"/> <property name="lastName" column="last_name"/> </component>
</class> < /hibernate-mapping>
注意:version 节点必须出现在ID 节点之后。
在这里我们声明了一个version属性,该属性用于存放用户的版本信息。我们对user表每一次更新操作,都会引起version属性的变化:加1。如果我们尝试在tx.commit 之前,启动另外一个Session,对名为同一个用户进行操作,就是并发更新的情形了: [java]
public void update(){ //开启事务tx1 Session session1 = HibernateUtil.getSession(); Transaction tx1 = session1.beginTransaction(); Users users1 = (Users) session1.get(Users.class, 1); //获取id为1的用户
//开启事务tx2 Session session2 = HibernateUtil.getSession();
Transaction tx2 = session2.beginTransaction(); Users users2 = (Users) session2.get(Users.class, 1); //获取id为1的用户
users1.getName().setFirstName("first name1");
users2.getName().setFirstName("first name2");
tx1.commit(); //..........1 tx2.commit(); //..........2
session1.close();
session2.clear();
}
执行以上代码,代码将在.....2处抛出StaleObjectStateException异常,并指出版本检查失败。
在这里是先提交者成功,后提交者失败。当前事务正在试图提交一个过期数据。通过捕捉这个异常,我们就可以在乐观锁校验失败时进行相应处理。
posted on 2013-05-04 18:08 wodekafeimao 阅读(156) 评论(0) 收藏 举报