Hibernate事务
Hibernate的任何对数据有改动的操作,都应该被放在事务里面。
在事务中的多个操作行为,要么都成功,要么都失败。
效果
在同一个事务中做了两件事情
- 删除id=1的产品
- 修改id=2的产品,使得其产品名称超过了数据库中设置的长度30. 提交事务。
第二个任务失败了,但是因为在同一个事务中,所以第一个任务也没有生效。因此id=1的产品,依然保留下来了。
代码
public class TestHibernate {
public static void main(String[] args) {
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Product p = (Product) s.get(Product.class, 1);
s.delete(p);
Product p2 = (Product) s.get(Product.class, 2);
p2.setName("长度超过30的字符串作为产品名称长度超过30的字符串作为产品名称长度超过30的字符串作为产品名称长度超过30的字符串作为产品名称");
s.update(p2);
s.getTransaction().commit();
s.close();
sf.close();
}
}
Hibernate属性的延迟加载(懒加载)
当使用load的方式来获取对象的时候,只有访问了这个对象的属性,hibernate才会到数据库中进行查询。否则不会访问数据库
代码
public class TestHibernate {
public static void main(String[] args) {
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Product p = (Product)s.load(Product.class, 1); //使用load的方式来获取对象
System.out.println("log1");
System.out.println(p.getName()); //访问产品名称属性
System.out.println("log2");
s.getTransaction().commit();
s.close();
sf.close();
}
}
效果
由上图可见在打印log1之前,是不会打印出sql语句的,只有在访问属性“getName()"的时候,才会访问数据库,并打印log2
要注意的是:
使用load访问对象时,获得该对象的id(即主属性),不访问数据库;
当访问非主属性(name)之类的就会访问数据库,执行数据库查询了;
package Test;
import hibernate.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class UserDao {
static SessionFactory sf = new Configuration().configure().buildSessionFactory();
static Session s = sf.openSession();
public User read() {
Transaction t = s.beginTransaction();
User user = (User) s.get(User.class, 1);
System.out.println(user.getId() + "\t" + user.getName());
t.commit();
return user;
}
public static User load() {
Transaction t = s.beginTransaction();
for (int i = 0; i < 10; i++) {
User p = new User();
p.setName("User"+i);
s.save(p);
}
User user = (User) s.load(User.class, 1);
System.out.println("log1");
System.out.println(user.getId()); //使用load访问对象时,获得该对象的id(即主属性),不访问数据库
System.out.println("log2");
System.out.println(user.getName()); //当访问非主属性(name)之类的就会访问数据库,执行数据库查询了
t.commit();
return user;
}
public static void main(String[] args) {
User read = load();
//System.out.println(read.getName()); //对象是从数据库加载的
}
}
Hibernate延迟加载
延迟加载又叫lazyload,在one-many many-many的时候都可以使用关系的延迟加载
当Category.hbm.xml中lazy="true"时,表示通过Category获取产品是延迟加载的
package com.test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.pojo.Category;
public class TestHibernate {
public static void main(String[] args) {
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Category c = (Category) s.get(Category.class, 1); //获取category对象
System.out.println("log1");
System.out.println(c.getProducts()); //通过category取products
System.out.println("log1");
s.getTransaction().commit();
s.close();
sf.close();
}
}
执行15行的时候,只会查询Category表的信息,不会查询product_表;
只有在执行18行,通过category取products的时候,才会进行对product_表的查询
但如果没设置延迟加载,则会查询所有的表;
Hibernate级联
什么是级联?
简单的说,没有配置级联的时候,删除分类,其对应的产品不会被删除。 但是如果配置了恰当的级联,那么删除分类的时候,其对应的产品都会被删除掉。
级联有4种类型:
all:所有操作都执行级联操作;(all 就是 delete+save-update)
none:所有操作都不执行级联操作;
delete:删除时执行级联操作;
save-update:保存和更新时执行级联操作;
级联通常用在one-many和many-to-many上,几乎不用在many-one上。
- delete 级联
Category.hbm.xml 加上:
set name=“products” cascade=“delete” lazy="false"
Category.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.pojo">
<class name="Category" table="category_">
<id name="id" column="id">
<generator class="native">
</generator>
</id>
<property name="name" />
<set name="products" cascade="delete" lazy="false">
<key column="cid" not-null="false" />
<one-to-many class="Product" /> <!--一对多关系-->
</set>
</class>
</hibernate-mapping>
在一对多代码的基础之上,修改TestHibernate.java为:
package com.how2java.test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.how2java.pojo.Category;
public class TestHibernate {
public static void main(String[] args) {
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Category c = (Category) s.get(Category.class, 3);
s.delete(c); //删除该分类后,该分类下的所有产品也被删除
s.getTransaction().commit();
s.close();
sf.close();
}
}
- save-update 级联
为Category.hbm.xml 加上:
set name=“products” cascade=“save-update” lazy="false"
<?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.pojo">
<class name="Category" table="category_">
<id name="id" column="id">
<generator class="native">
</generator>
</id>
<property name="name" />
<set name="products" cascade="save-update" lazy="false">
<key column="cid" not-null="false" />
<one-to-many class="Product" />
</set>
</class>
</hibernate-mapping>
在一对多代码的基础之上,修改TestHibernate.java为:
package com.test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.how2java.pojo.Category;
import com.how2java.pojo.Product;
public class TestHibernate {
public static void main(String[] args) {
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Category c = (Category) s.get(Category.class, 5);
Product p1 = new Product(); //新建3个产品
p1.setName("product_501");
Product p2 = new Product();
p2.setName("product_502");
Product p3 = new Product();
p3.setName("product_503");
c.getProducts().add(p1); //向分类中加产品
c.getProducts().add(p2);
c.getProducts().add(p3);
s.getTransaction().commit();
s.close();
sf.close();
}
}
运行代码就会发现,这3个瞬时状态的产品对象虽然没有添加到数据库里(没有用s.save(p1)),但是在事务提交的时候,会把他们3个持久化。 如果没有cascade=“save-update”,就会报错