一:搭建hibernate的使用环境
二:对象在hibernate中的三种状态、增(增加完成后可以返回该条数据的主键)删改查、分页查询、总记录查询
三:hibernate中的关系
四:缓存分析
五:事务、延迟加载、乐观锁(version)、C3PO连接池(现在来讲,比较古老了)、两种session的获取与区别
六:总结
一:搭建hibernate的使用环境
要使用hibernate完成对数据库的持久化操作,首先要实现以下配置:
①在eclipse的java Project项目中导入hibernate所必须的jar包;
②在src下新建hibernate.cfg.xml主配置文件----设置数据库连接、配置hibernate具备的属性、导入实体类映射文件等
<?xml version="1.0" encoding="UTF-8"?> com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/sh?characterEncoding=UTF-8 root root
<!-- hibernate配置 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="current_session_context_class">thread</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<!-- 映射文件 -->
<mapping resource="hibernate/Hero.hbm.xml"/>
</session-factory>
1
2
3
4
5
6
7
8
此配置中声明了hibernate连接那个数据库,以及对hibernate的设置,
dialect是告诉数据库我连接的是MySQL,请在生成SQL语句或者其他操作时,按照MySQL的语法来执行;
current_session_context_class是hibernate的事务管理方式,即每个线程代表一个事务;
show_sql为true时,是配置了在控制台打印生成的SQL语句;
hbm2ddl.auto这个配置代表自动更新表结构,也就是hibernate可以自动的在数据库中创建表。无需自行创建。
mapping resource指向了实体类与数据库字段做映射的配置文件路径。
③src下新建pojo包,创建实体类Hero.java,设置name和id属性,并给出get、set方法;
④src下新建hibernate文件夹,创建Hero.hbm.xml文件
<?xml version="1.0" encoding="UTF-8"?> package指向的是该实体类所在的包,以src为根目录。
标签即代表一个映射类。在该标签属性中,name属性是对应的package包下的需要进行映射的实体类,table对象数据库中的表名。
在class标签中,必须设置,因为他声明了该表的主键对应实体的那个属性。name是属性名,column代表对应哪个字段,该配置是说该id的增长方式按照配置的数据库的增长方式来(例如数据库中没有该表,则hibernate会创建这个表,并设置id为主键,设置为自增长)
该标签是配置除主键外其他的属性与字段的映射关系,name是属性,column是字段。
⑤src下新建action包,创建Test.java文件
public class Test {
public static void main(String[] args) {
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Hero hero = new Hero();
hero.setName(“女警”);
s.save(hero);
s.getTransaction().commit();
s.close();
sf.close();
}
}
此时,右键运行该文件,则数据库中会生成hero表,并插入了一条数据。一套完整的hibernate配置搭建就完成了并能够成功运行。此时就能够感受到,hibernate的面向对象的思想,通过操作对象的方式完成对数据的持久化。似不似很方便了。
二:增删改查
对象在hibernate中的三种状态:瞬时、持久、托管。
当对象被new创建,并设置了属性值,没有跟hibernate发生任何关系,JVM停止运行,该对象就烟消云散。此时为瞬时状态
该对象与hibernate发生了关系,并且有对象的session,在数据库中有对应的记录,且该对象存在session的缓存中。则该对象为持久化状态。
该对象在数据库中有对应的一条记录,但是session被关闭了,该对象不存在session的缓存中了。对象不能跟数据库进行通讯,它恢复成了一个普通的对象了。此时为托管状态。例如通过session的get方法获取到id为1的hero对象,然后session关闭了,hero对象虽然有个数据库查询出来的值,但它此时仅仅是一个hero对象,修改它与数据库没有任何关系了。
对于session对象来讲,他就是代表一次程序与数据库的对象,当它开启后,相当于设置了映射关系的对象就可以与数据库进行通讯,通过修改对象完成对数据库的操作。此时对象就是处于持久化的状态。当session关闭后,通讯切断。程序恢复正常。
通过hibernate完成数据库的操作过程中,大多可遵循以下顺序:
创建sessionFactory, 通过sessionFactory打卡一个session对象,该session对象开启一个事务(相对于开启一个线程)
执行数据库操作逻辑,session对象提交事务,关闭session,关闭sessionFactory。
以增加为例,如下:
public class Test {
public static void main(String[] args) {
//创建sessionFactory
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();//通过sessionfactory打开一个session对象
s.beginTransaction();//session对象开启一个事务
Hero hero = new Hero();
hero.setName(“女警”);
s.save(hero);//执行数据库操作
s.getTransaction().commit();//session对象提交事务
s.close();//关闭session
sf.close();//关闭sessionfactory
}
}
在此过程中,当session.save方法执行之后,其实可以观察到数据已经传递到数据库那里去了,相当于在程序与数据库之间,有一个中间层,当执行save方法之后,该数据被放到了中间层,只有在session把该事物提交之后,才真正的锤落定音,持久化到了数据库中。之前我们在hibernate.cfg.xml配置文件声明了一个事务一个线程,因为事务具有线程不安全性,所以我们在使用hibernate时,要做到一个数据库操作创建一个session,使用完后关闭掉。
使用save保存一条数据可以通过int id = (Integer)s.save(hero)这种方式获取到save返回来的这条数据的主键。
删除即调用session的delete(hero)即可完成
修改调用update(hero)即可完成,这里通过get(实体类.class,id值)的方式获取id为1的对象,然后修改该对象的属性,执行update完成更新,如下:
public class Test {
public static void main(String[] args) {
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Hero hero = new Hero();
hero = (Hero)s.get(Hero.class, 1);
hero.setName=“女警改1”;
s.update(hero);
s.getTransaction().commit();
s.close();
sf.close();
}
}
4. 查询就有点多样化了。
①首先可以通过get()或者 load()方法获取,这两种方法的区别会在下面进行介绍。
②通过hql获取,hibernate的专门用于查询的语句,不同于sql,比如hql在查询时,使用类名而不是表明,select Hero where id=1
public class Test {
public static void main(String[] args) {
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
String name = “女”;
Query q =s.createQuery(“from Hero p where p.name like ?”);
q.setString(0, “%”+name+"%");
List ps= q.list();
for (Hero p : ps) {
System.out.println(p.getName());
}
s.getTransaction().commit();
s.close();
sf.close();
}
}
即完成了对hero表中的数据进行模糊查询,并通过q.list(),返回查询到的数据集合。
③SQL,同样使用SQL进行模糊查询如下:
String name = "女";
String sql = "select * from hero where name like '%"+name+"%'";
Query q= s.createSQLQuery(sql);
List<Object[]> list= q.list();
for (Object[] os : list) {
for (Object filed: os) {
System.out.print(filed+"\t");
}
System.out.println();
}
1
2
3
4
5
6
7
8
9
10
使用SQL查询list返回的是一个object类型的集合。
④Criteria进行查询,这种查询方式是完全面对对象的方式进行查询:
String name = "女";
Criteria c= s.createCriteria(Hero.class);
c.add(Restrictions.like("name", "%"+name+"%"));
List<Hero> ps = c.list();
for (Hero p : ps) {
System.out.println(p.getName());
}
1
2
3
4
5
6
7
有关更多Criteria的使用方法,可以查询hibernate的官方文档或者论坛使用手册。
对于分页查询和总记录查询:
可以事情hql查询,调用q.uniqueResult()方法获取总数。
String name = "女";
Query q =s.createQuery("select count(*) from Hero where name like ?");
q.setString(0, "%"+name+"%");
long total= (Long) q.uniqueResult();
System.out.println(total);
1
2
3
4
5
hibernate的分页查询,hibernate使用Criteria来进行分页查询,使用十分的简单。
c.setFirstResult(2); 表示从第3条数据开始
c.setMaxResults(5); 表示一共查询5条数据
String name = "女";
Criteria c= s.createCriteria(Hero.class);
c.add(Restrictions.like("name", "%"+name+"%"));
c.setFirstResult(2); //表示从第三条数据开始,相当于limit的第一个参数
c.setMaxResults(5); //显示5条数据,相当于limit的第二个参数
1
2
3
4
5
三:hibernate中的关系
多对一、一对多、多对多关系。
多对一:
多个Product对应一个Category ,大致理解就是,在product类中增加Category属性,在保存该product时,设置setCategory属性。此时通过配置映射文件中的多对一关系,会在product表中自动添加cid(cid的值为该Category对象的主键)作为该表的外键。
创建Product、Category类,并配置映射文件。在Product.hbm.xml文件中配置增加多对一关系。代表Product类中的category属性对应的是Category这个映射类,并对应product数据库中的cid。
将这两个映射文件添加到hibernate.cfg.xml中,在test类中,此时更新p时,p的cid即为c对象的主键id。
Category c =new Category();
c.setName("c1");
s.save(c);
Product p = (Product) s.get(Product.class, 8);
p.setCategory(c);
s.update(p);
1
2
3
4
5
6
一对多
一个Category对应多个Product ,大概意思就是一个分类中有多个产品,在Category实体中增加属性set products代表这个Category对象中的product集合。在Category映射文件中配置了一对多关系后,查询一条Category对象的值,通过获取products属性,就可以获取到product表中cid的值为该Category对象主键的所有product记录。
配置文件如下:通过标签进行设置,因为我们的products属性是set类型的。name为该属性的名。lazy为是否延迟加载,有关延迟加载后面会有介绍。key代表这个表对应的外键是cid,为配置一对多关系,class为一对多的多是那个类。
在test.java 中,查询id为1的Category对象记录,并获取products属性,将该属性遍历输出,即可得到product表中所有cid为1的product记录。
Category c = (Category) s.get(Category.class, 1);
Set<Product> ps = c.getProducts();
for (Product p : ps) {
System.out.println(p.getName());
}
1
2
3
4
5
多对多
①一个用户User可以购买多个Product,一个product可以被多个User用户购买,则user和product为多对多关系。
②创建user类,user类中添加set products。product中添加set users属性。
③在user.hbm.xml中:设置多对多关系,也就是相当于给products这个属性设置多对多关系。并告诉数据库,user与product的对应关系保存在user_product这张表中。
key代表这个对象在user_product表中的主键,也就是说获取一条user对象时,然后查看他买了哪些product。需要去user_product表中寻找uid为user的主键的对应的所有pid记录,即该用户对应的多个product是哪些。
many-to-many中设置了class,也就是这个products集合属性对应的哪个类,column的意思是在user_product表中创建字段pid,当插入一个user记录时,获取到user中所有product对象,把对象的Product类中映射对应的主键,插入到这个pid中。一个uid可以对应多个pid。在数据库中形成一对多关系
代表user的id为1的对象对应了id为2,3,4,5的四个product对象。
---------------------