hibernate
概述
hibernate是一个ORM框架,ORM指的是对象关系映射,因为java程序中使用的是面向对象模型,而关系型数据库使用的是关系模型,这两种模式是不匹配的。所以在使用JDBC操作数据库时需要手动的进行两种模型的转换,有了ORM框架之后可以让ORM框架来完成两种模型的转换,我们只需要给出对应的映射就可以了,映射可以是XML或者注解。
说明:除了hibernate还有很多其他的ORM框架,很多ORM框架都是JPA的实现,包括OpenJPA、EclipseLink
POJO
POJO - Plain Ordinary Java Object
PO POJO+Annotation/XML
PO - Persistent Object
在pom.xml中添加依赖项
配置
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
在类路径下添加hibernate配置文件,默认文件名是hibernate.cfg.xml,建议不要改
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///hibernate?useUnicode=true&characterEncoding=utf8
</property>
<property name="connection.username">root</property>
<property name="connection.password">lcw123</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL方言 MySQL57代表mysql版本5.7 -->
<property name="dialect">org.hibernate.dialect.MySQL57Dialect</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider
</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!--<property name="hbm2ddl.auto">update</property> 正向工程,根据实体自动对象建表-->
<mapping class="com.lcw666.domain.hibernate.User"/>
</session-factory>
</hibernate-configuration>
映射实体类(通过注解的方式)
/* 如果需要建表时的写法,可以在 @Column在添加约束
@Entity
@Table(name="tb_user")
public class User implements Serializable{
@Id
@Column(length=20)
private String username;
@Column(name="userpass",length=20,nullable=false)
private String password;
@Column(unique=true)
private String email; */
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "tb_user")
public class User implements Serializable {
@Id
@Column(name = "userid")
@GeneratedValue(strategy = GenerationType.IDENTITY) // 映射主键生成策略
private Integer id;
private String username;
@Column(name = "userpass")
private String password;
private String email;
//getter and setter
}
映射实体类(通过xml配置的方式)
import java.io.Serializable;
public class User implements Serializable {
private String id;
private String username;
private String password;
private String email;
//getter and setter
}
实体映射文件-User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lcw666.hibernate.domain">
<class name="User1" table="tb_user1">
<id name="id" column="userid">
<generator class="uuid"/> //生成id的策略-uuid、increment、native等
</id>
<property name="username"/>
<property name="password" column="userpass"/>
<property name="email"/>
</class>
</hibernate-mapping>
对实体类的要求:
-
实体类不能用final修饰
-
实体类实现Serializable接口
-
实体类的属性最好不要使用基本数据类型
-
保留无参构造器
-
必须有ID属性
操作
通过hibernate来实现增删改查操作
public class AppTest{
@Test
public void testSave() {
User user = new User();
user.setUsername("lll");
user.setPassword(DigestUtils.md5Hex("123123"));
user.setEmail("lcww@qq.com");
Session session = HibernateUtil.getSession();
try {
session.beginTransaction();
Serializable key = session.save(user);
Assert.assertNotNull(key);
System.out.println(key);
session.getTransaction().commit();
} catch (Exception e) {
session.getTransaction().rollback();
e.printStackTrace();
}finally {
session.close();
}
}
@Test
public void testGet() {
Session session = HibernateUtil.getSession();
session.beginTransaction();
User user = session.get(User.class, 1);
session.getTransaction().commit();
session.close();
Assert.assertNotNull(user);
}
@Test
public void testGetByUsername() {
Session session = HibernateUtil.getSession();
session.beginTransaction();
User user = session.createQuery("from User as u where u.username=:username", User.class).setParameter("username", "lll").getSingleResult(); //如果找不到username,则抛出异常,而不是返回null
//Assert.assertNotNull(user);
System.out.println(user.getEmail());
//正确的做法
List<User> userList = session.createQuery("from User as u where u.username=:username", User.class).setParameter("username", "lfll").getResultList(); //如果找不到username,返回空集合
/*List<User> userList = session.createQuery("from User as u where u.username=:username", User.class)
.setParameter("username", "lfll")
.setFirstResult(0)
.setMaxResults(5)
.getResultList(); //分页查询,从第0条开始查,一次最大查5条记录 */
Assert.assertEquals(0, userList.size());
session.getTransaction().commit();
session.close();
}
@Test
public void testDelete() { //根据主键删除
// User user = new User();
// user.setId(1); 不安全,如要要删除的对象不存在,则抛出异常
Session session = HibernateUtil.getSession();
session.beginTransaction();
User user = session.get(User.class, 3);
if (user!=null) {
session.delete(user);
}
//session.remove(user); 和delete一样
session.getTransaction().commit();
session.close();
}
@Test
public void testDeleteByUsername() { //根据用户名删除
Session session = HibernateUtil.getSession();
session.beginTransaction();
int affectedRows = session.createQuery("delete from User as u where u.username = :uid")
.setParameter("uid", "ll").executeUpdate();
Assert.assertEquals(0, affectedRows);
session.getTransaction().commit();
session.close();
}
}
类和类之间的继承关系和关联关系可以映射到关系型数据库中
继承映射
关联映射
一对一
一对多
多对多
其他
-
清理一级缓存
一级缓存:Session里面容器保存的内容
- Session.clear();
- Session.evict(obj); 清理某个对象
-
hibernate中的对象状态
- 瞬时态(transient)- 创建一个对象,Session中没有缓存该对象,数据库中也没有与之对应的记录,此时对象处于瞬时态,瞬时态对象通过Session的save、savaOrUpdate、persist方法可以变成持久态。
- 持久态(persistent)- 如果数据库中持有对象对应的记录,而且对象被纳入一级缓存(session)中,此时对象处于持久态,持久态的对象直接调用对象的setter方法就可以完成更新操作,不需要调用Session对象的update方法,持久态对象通过调用Session的evict、clear、close方法变成游离态,通过调用对象的delete或者remove方法会变成瞬时态(删除态)。
- 游离态(detached)/脱管态 - 如果对象在数据库中有之对应的记录,但是Session中没有改对象(脱离了一级缓存的管理),此时对象处于游离态,如果希望对象从游离态回到持久态可以使用update方法。如果希望对象更新对象但又不让对象回到持久态应该使用merge方法,而不是update。
-
hibernate锁
悲观锁
所谓悲观锁就是悲观的认为并发数据访问的冲突会经常性的发生,所以需要将数据锁住避免发生数据读写问题。
下面get方法的第三个参数用来设置悲观锁
Dept dept = session.get(Dept.class, 1,LockMode.PESSIMISTIC_READ);
-
LockMode.PESSIMISTIC_READ - 我读的时候他人可以读不能写
-
LockMode.PESSIMISTIC_WRITE - 我写的时候他人可以读不能写
悲观锁需要锁定行或者表,这就意味着没有并发,所以性能较差。
乐观锁
乐观的认为并发数据访问冲突不会经常性的发生,如果发生了也不要紧,通过版本号来确定是否能够进行写数据的操作.
在实际开发中尽量使用乐观锁来替代悲观锁的使用。