Hibernate入门(一)
文章目录
一、Hello World
-
添加maven依赖
<!-- hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.4.1.Final</version> </dependency> <!-- mysql connection --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency>
-
编写hibernate.cfg.xml文件
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 告诉hibernate使用的是哪种数据库 --> <property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </property> <!--配置数据源--> <!-- 数据库驱动类 --> <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property> <!-- jdbc url --> <property name="hibernate.connection.url"> jdbc:mysql://localhost:3306/test </property> <property name="hibernate.connection.username"> root </property> <property name="hibernate.connection.password"> 11111 </property> <!--是否显示sql--> <property name="show_sql">true</property> <!--格式化显示sql--> <property name="format_sql">true</property> <!-- List of XML mapping files --> <mapping resource="Employee.hbm.xml"/> </session-factory> </hibernate-configuration>
-
编写表与类,字段与属性的映射文件
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!-- 做表与类的映射; 一个hbm文件对应一张表和一个类的映射关系 --> <hibernate-mapping> <!--name的值为:包名.类名,table为对应的表--> <class name="hibernate.Employee" table="EMPLOYEE"> <!--元数据描述 可以去掉--> <!--<meta attribute="class-description"> This class contains the employee detail. </meta>--> <!-- id 指的是作为主键的字段,所以需要单独进行处理; name:属性名; column: 列名; type:字段的类型; --> <id name="id" type="int" column="id"> <!-- 这是主键的生成策略 increment:自增长 Oracle数据库,也可以配置increment 先查询要插入的表的id的最大值max, 执行max = max + 1, 将计算结果作为id。 sequence:序列 uuid:使用uuid算法生成主键 native:本地,hibernate自动根据数据库选择主键生成策略 mysql:increment oracle: sequence,hibernate会默认使用一个叫做 hibernate_sequence的序列,而且该序列所有的pojo共享 --> <generator class="native"/> </id> <property name="firstName" column="first_name" type="string"/> <property name="lastName" column="last_name" type="string"/> <property name="salary" column="salary" type="int"/> </class> </hibernate-mapping>
-
编写测试类
package hibernate;
// 实体类
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
public Employee() {
}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String first_name) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String last_name) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
package hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class TestMain {
private static SessionFactory factory = null;
public static void main(String[] args) {
// 读取hibernate的配置文件
// 配置文件默认是根目录下的hibernate.cfg.xml文件
Configuration config = new Configuration();
// 如果配置文件的名字不是hibernate.cfg.xml
// 可以使用重载方法,指定文件名。
// config.configure("hibernate.xml");
config.configure();
// 创建sqlSessionFactory
factory = config.buildSessionFactory();
System.out.println("id1 = " + addEmployee("111", "222", 10000));
System.out.println("id2 = " + addEmployee("aaa", "bbb", 20000));
System.out.println("id3 = " + addEmployee("ccc", "ddd", 30000));
}
public static int addEmployee(String fname, String lname, int salary) {
// 获取sqlsession
Session session = factory.openSession();
// 事务
Transaction tx = null;
Integer employeeId = null;
try {
// 开启事务
tx = session.beginTransaction();
Employee e = new Employee(fname, lname, salary);
// 调用session API,插入到Employee表里,返回值为employeeId
employeeId = (Integer) session.save(e);
//提交事务
tx.commit();
} catch (HibernateException e) {
// 发生异常,如果开启了事务,事务回滚
if (tx != null) {
tx.rollback();
}
System.err.println(("插入数据库失败 --- >" + e.getMessage()));
} finally {
session.close();
}
return employeeId;
}
}
/*output :
Hibernate:
insert
into
EMPLOYEE
(first_name, last_name, salary)
values
(?, ?, ?)
id1 = 4
Hibernate:
insert
into
EMPLOYEE
(first_name, last_name, salary)
values
(?, ?, ?)
id2 = 5
Hibernate:
insert
into
EMPLOYEE
(first_name, last_name, salary)
values
(?, ?, ?)
id3 = 6
*/
二、核心API
2.1 save()
参考Hello World
保存执行结束,对象由临时态变成持久态
2.2 delete()
public static void delEmployee(int id) {
//获取sqlsession
Session session = factory.openSession();
//事务
Transaction tx = null;
try {
//开启事务
tx = session.beginTransaction();
// delete也是根据对象进行操作的。
Employee e = new Employee();
e.setId(id);
session.delete(e);
// 提交事务
tx.commit();
} catch (HibernateException e) {
// 如果事务已经开启,回滚事务
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
// 关闭session
session.close();
}
}
首先我先清空了employee这张表,调用了delEmployee方法,会报错
Hibernate:
delete
from
EMPLOYEE
where
id=?
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed:
调用addEmployee()方法,在调用delEmployee()方法可删除成功。
System.out.println("id1 = " + addEmployee("111", "222", 10000));
// System.out.println("id2 = " + addEmployee("aaa", "bbb", 20000));
// System.out.println("id3 = " + addEmployee("ccc", "ddd", 30000));
delEmployee(1);
如果id为null,则不执行语句
删除的对象必须是 持久态对象或者 游离态对象
2.3 load()
根据id查询某个对象
/**
* 根据id获取employee
*
* 这个方法,会报错, org.hibernate.LazyInitializationException: could not initialize proxy [hibernate.Employee#2] - no Session
* load方法的执行则比较复杂首先查找session的persistent Context(一级缓存)中是否有缓存,
* 如果有则直接返回,如果没有则去查找二级缓存,如果有则返回,
* 如果没有则判断是否是lazy,若不是lazy,直接访问数据库检索,
* 查到记录返回,并且同时在二级缓存中存放查到的数据方便下次使用,
* 若再下次使用时在二级缓存命中,就是查到数据,则有可能将数据放到一级缓存中。
* 若是lazy,则返回代理对象,查不到抛出异常,而不到数据库中查找,除非使用此对象时,才到数据库中查找
*
* @param id
* @return
*/
public static Employee loadEmployeeById(Integer id) {
//获取sqlsession
Session session = factory.openSession();
//事务
Transaction tx = null;
try {
//开启事务
tx = session.beginTransaction();
Employee e = session.load(Employee.class, id);
// 提交事务
tx.commit();
return e;
} catch (HibernateException e) {
// 如果事务已经开启,回滚事务
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
// 关闭session
session.close();
}
return null;
}
这个方法,会报错, org.hibernate.LazyInitializationException: could not initialize proxy [hibernate.Employee#2] - no Session。load方法的执行则比较复杂首先查找session的persistentContext(一级缓存)中是否有缓存,如果有则直接返回,如果没有则去查找二级缓存,如果有则返回,如果没有则判断是否是lazy,若不是lazy,直接访问数据库检索,查到记录返回,并且同时在二级缓存中存放查到的数据方便下次使用,若再下次使用时在二级缓存命中,就是查到数据,则有可能将数据放到一级缓存中。若是lazy,则返回代理对象,查不到抛出异常,而不到数据库中查找,除非使用此对象时,才到数据库中查找。上述写法是打开一个新的session,session不一样,所以会报no session
如果id不存在,报错
No row with the given identifier exists: [类#ID]
如果实体(的hbm)没有映射到cfg中,报错
Unknown entity: 实体类
2.4 get()
/**
* 根据id获取employee
*
* @param id
* @return
*/
public static Employee getEmployeeById(Integer id) {
//获取sqlsession
Session session = factory.openSession();
//事务
Transaction tx = null;
try {
//开启事务
tx = session.beginTransaction();
Employee e = session.get(Employee.class, id);
// 提交事务
tx.commit();
return e;
} catch (HibernateException e) {
// 如果事务已经开启,回滚事务
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
// 关闭session
session.close();
}
return null;
}
/*output
Hibernate:
select
employee0_.id as id1_0_0_,
employee0_.first_name as first_na2_0_0_,
employee0_.last_name as last_nam3_0_0_,
employee0_.salary as salary4_0_0_
from
EMPLOYEE employee0_
where
employee0_.id=?
Employee{id=2, firstName='aaa', lastName='bbb', salary=20000}
*/
如果id不存在,返回null
如果实体(的hbm)没有映射到cfg中,报错
Unknown entity: 实体类
2.5 load()和get()的区别
-
id不存在:
- load:报错
- get: 返回null
-
从检索执行机制上对比:
-
load:
load方法的执行则比较复杂首先查找session的一级缓存中是否有缓存,如果有则直接返回,如果没有则去查找二级缓存,如果有则返回,如果没有则判断是否是lazy,若不是lazy,直接访问数据库检索,查到记录返回,并且同时在二级缓存中存放查到的数据方便下次使用,若再下次使用时在二级缓存命中,就是查到数据,则有可能将数据放到一级缓存中。若是lazy,则返回代理对象,查不到抛出异常,而不到数据库中查找,除非使用此对象时,才到数据库中查找。
-
get:
get方法不能使用延迟加载,get方法先到一级缓存,然后二级,最后db查找。
-
2.6 update()
public static void updateEmployee(Integer EmployeeID, int salary ){
Session session = factory.openSession();
Transaction tx = null;
try{
tx = session.beginTransaction();
Employee employee =
(Employee)session.get(Employee.class, EmployeeID);
employee.setSalary( salary );
session.update(employee);
tx.commit();
}catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}finally {
session.close();
}
}
/*output
Hibernate:
select
employee0_.id as id1_0_0_,
employee0_.first_name as first_na2_0_0_,
employee0_.last_name as last_nam3_0_0_,
employee0_.salary as salary4_0_0_
from
EMPLOYEE employee0_
where
employee0_.id=?
Hibernate:
update
EMPLOYEE
set
first_name=?,
last_name=?,
salary=?
where
id=?
*/
如果ID不存在 , 报错
Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
注意:如果重新创建了一个对象,其他列会被更新成null
Employee employee = new Employee();
employee.setId(2);
employee.setSalary(22000);
// fname,lname列会被更新为null
2.7 saveOrUpdate()
- 如果对象id为null --> save
- 如果对象id不为null,并且在数据库中存在 --> update
- 如果对象id不为null,并且在数据库中不存在 –> 报错
2.8 createQuery()
public static void getAllEmployees() {
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
List<Employee> employees = session.createQuery("FROM Employee",Employee.class).list();
Iterator<Employee> iterator = employees.iterator();
while (iterator.hasNext()) {
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " + employee.getFirstName());
System.out.print(" Last Name: " + employee.getLastName());
System.out.println(" Salary: " + employee.getSalary());
}
tx.commit();
} catch (HibernateException e) {
if (tx != null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/*
* output
* Hibernate:
* select
* employee0_.id as id1_0_,
* employee0_.first_name as first_na2_0_,
* employee0_.last_name as last_nam3_0_,
* employee0_.salary as salary4_0_
* from
* EMPLOYEE employee0_
* First Name: 111 Last Name: 222 Salary: 15000
* First Name: aaa Last Name: bbb Salary: 20000
* First Name: ccc Last Name: ddd Salary: 30000
*/