Hibernate
hibernate在hibernate.cfg.xml中配置数据库驱动,url,账号密码等
hibernate是有3种状态的,分别是瞬时、持久、脱管。其中new className()时数据库中还没有对应记录,这个时候className对象的状态是瞬时。
通过session的save把该对象保存在了数据库中,该对象也和session产生了联系,此时的状态应该是持久的。
最后把session关闭了,这个对象在数据库中有了对应的数据,但是已经和session失去了联系,相当于脱离了管理,状态是脱管。
Hibernate有五大接口,分别是session、Query、Sessionfactory、configuration、Translation,
1、实例化的session是一个轻量级的类,它的创建和注销都不会产生太大的损失,在设计中最好是一个线程只创建一个session对象,session可以看作介于数据库连接与事务管理之间的一种接口,可以将session想象成一个持久的缓冲区,Hibernate能检测到这些持久层对象的改变,并及时刷新数据库,以及从数据库获得他们
2、SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,负责创建Session对象,用到了工厂模式,这里的sessionFactory并不是轻量级的,在一般情况下一个项目只需要一个SessionFactory,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory
3、Transaction接口负责事务相关操作,一般在Hibernate的增删查改中出现,但是使用Hibernate的人一般使用spring去管理事务
4、Query负责执行各种数据库查询,它可以使用HQL或者SQL语言,返回值一般是List
5、Configuration对象用于配置并启动Hibernate,Hibernate应用通过Configuration实例来指定对象关系映射文件的位置或者动态配置Hibernate的属性,然后创建SessionFactory
循行顺序为:
1、应用程序先调用Configuration类读取该类中的配置信息
2、使用这些信息生成SessionFactory对象,再使用sessionFactory对象生成session对象
3、使用session对象生成Transaction对象
4、通过session对象进行加载、保存、更新、删除等操作
5、在查询情况下可以通过session对象生成Query对象,然后利用Query对象执行查询操作,如果没有异常的话Transaction对象将这些操作提交到数据库中
hibernate有两种面向对象的查询方法,分别是criteria和hql
hibernate有多对一,一对多,多对多的关系。例如Product和Category是多对一的关系,则应该在Product.hbm.xml文件中设置<many-to-one>,再在hibernate.cfg.xml中增加Category的映射。
public class CategoryDAOImpl implements zhongfucheng.dao.CategoryDao{ @Override publicvoidaddCategory(Category category) { QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource()); String sql = "INSERT INTO category (id, name, description) VALUES(?,?,?)"; try { queryRunner.update(sql, new Object[]{category.getId(), category.getName(), category.getDescription()}); } catch (SQLException e) { throw new RuntimeException(e); } } @Override public Category findCategory(String id) { QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource()); String sql = "SELECT * FROM category WHERE id=?"; try { Category category = (Category) queryRunner.query(sql, id, new BeanHandler(Category.class)); return category; } catch (SQLException e) { throw new RuntimeException(e); } } @Override public List<Category> getAllCategory() { QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource()); String sql = "SELECT * FROM category"; try { List<Category> categories = (List<Category>) queryRunner.query(sql, new BeanListHandler(Category.class)); return categories; } catch (SQLException e) { throw new RuntimeException(e); } } }
要比较hibernate和传统的DBUtil的区别,就先看看传统方式是怎么进行crud的,如果是插入一个新的数据,则将对象的属性进行拆分,然后拼装成SQL语句。
在进行查询时,则是将sql数据的属性拼装成javabean对象,其操作时十分繁琐的。但是如果使用hibernate则直接对对象进行操作。
package com.how2java.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; 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(); Product p =(Product) s.get(Product.class, 5); s.delete(p); s.getTransaction().commit(); s.close(); sf.close(); } }
简直不要太简单!!!
假设在一个事务中做了两件事情,第一件事情执行成功但是第二件事情执行失败,则第一个事务执行也就不会生效,只有在表的类型是INNODB时才支持事务
hibernate支持级联操作,作为级联是指在数据库中多个表的对应关系,假设有一张教师信息表,表中的属性有教师的年龄手机号码家庭住址等信息,另一张表是老师和所带的班级之间的信息,一个班级对应一个老师,包括老师的手机号码,如果在表1 中改变老师张三的手机号码,如果设置了级联,则表二中张三的手机号码也会改变
级联一共有四种:
all:所有的操作都执行级联操作
none:所有的操作都不执行级联操作
delete:删除时执行级联操作
save-update:保存和更新时执行级联操作
级联操作通常在one-many和many-to-many上,几乎不使用在many-one上。
Hibernate的一级缓存和二级缓存
使用缓存是为了减少对数据库的操作次数,从而提高执行效率,Hibernate的一级缓存是也叫做session缓存,它可以在session的范围内减少数据库的访问次数,若session关闭,则一级缓存失败。当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,会把对象放入session中,session是由hibernate维护的,可以通过hibernate的evict/clear方法操作,不同session不会共享数据。
使用二级缓存时,需要在hibernate.cfg.xml中开启二级缓存配置,hibernate本身不提供二级缓存,都是使用第三方的二级缓存插件,
<property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
二级缓存可以跨越多个session,即不同的session都可以访问缓存数据
hibernate的懒加载是当用到数据的时候猜想数据库查询,这就是hibernate的懒加载,使用懒加载是为了提高程序的执行效率
get()方法,及时加载,只要调用该方法就立即向数据库查询
load()方法,默认懒加载,即在使用数据的时候才想数据库发送查询,session关闭后不可以使用懒加载,当session关闭后使用懒加载则会报错,解决方法:
1在关闭session之前使用一下数据,这样数据就缓存在session中了,关闭后依旧正常使用数据。
2关闭懒加载
3强迫代理对象初始化操作:Hibernate.initialize
4在使用完数据之后在关闭session
在对属性不存在的对象处理时,例如查询id=999的对象,而该对象不存在时,get方法会返回null而load方法会抛出异常
Hibernate中的query.list()与query.iterator()方法的区别
1、list()方法返回的是一个List二iterator()方法返回的是iterator
2、获取数据的方式不一样,list()会直接查询数据库,iterator()会先到数据库中把id都取出来,然后真正要遍历某个对象的时候先到缓存找,如果找不到则以id为条件再发一条sql到数据库,如果缓存中没有数据,则查询数据库的次数是n+1
3、iterator会查询二级缓存,list只查询数据库。
4、list()中返回的List中的每个对象都是原本的对象,iterator中返回的对象是代理对象
5、list()方法会一次去除所有的结果集对象,而且他会依据查询的结果初始化的结果集对象,如果结果集非常大则可能造成内存泄露的情况
6、iterator()方法在执行时不会一次初始化所有的对象,而是根据对结果集的访问情况来初始化对象,可以控制缓存中的对象数量,以避免占用过多的缓存,导致内存溢出的发生。
Hibernate有两种方法获得session,分别是openSession和getCurrentSession区别在于:
1、openSession每次都会得到一个新的Session对象,getCurrentSession在同一个线程中每次都是获得相同的Session对象,但是在不同的线程中获取的是不同的Session对象。
2、openSession只有在增加、删除、修改的时候需要事务,查询的时候不需要。getCurrentSession是自由所得操作都必须放在事务中进行,并且提交事务后session会自动关闭,不需要再进行关闭。
hibernate的乐观锁是通过version的值来控制对数据库的存取
乐观并发控制可以有三种方式
Version版本号
时间戳
自动版本控制
仅说明版本好控制的过程
假设数据库中的产品的价格是1000,version是10,session1、session2分别获取了该对象并且都要修改该对象的价格,
session1试图保存到数据库,检测version依旧等于10,成功保存,并把version修改为11
session2试图保存到数据库,检测到version=11,说明改数据已经被其他进程访问过了,保存失败,抛出异常
hibernate连接池
建立数据库连接是比较消耗时间的,通常会采用数据库连接池来建立多天数据链接,并且持续使用,从而节约建立数据库链接所需要的时间,hibernate常用的数据库连接池是C3P0。具体配置不再细说
hibernate的注解
对于一个JavaBean类要建立一个JavaBean.hbm.xml是极其麻烦的,使用
package com.how2java.pojo; 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 = "product_") public class Product { int id; String name; float price; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") public int getId() { return id; } public void setId(int id) { this.id = id; } @Column(name = "name") public String getName() { return name; } public void setName(String name) { this.name = name; } @Column(name = "price") public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } }
可以不用建立JavaBean.hbm,xml就可以;
把Product的getCategory进行多对一映射
@ManyToOne 表示多对一关系
@JoinColumn(name="cid") 表示关系字段是cid
对比xml中的映射方式: