一.Java3大框架在三层结构中的使用
- web层(视图层) :struts2
- service层(服务层) :spring
- dao层(数据库操作层) :hibernate
二.hibernate概述
1.hibernate框架概述
> hibernate是Javaee中3层架构的dao层,也就是数据持久化层.
> hibernate是对jdbc进行的封装,简化数据库的操作
> hibernate是开源的,轻量级的框架
2.hibernate的orm思想(object,relational,mapping),对象关系映射
> hibernate的orm思想是将实体类和数据库表进行一一对应,即实体类属性和数据库字段名字一样.
> 操作的时候,不需要操作数据库,而是操作实体类对象.
三.hibernate入门
1.创建一个hibernate项目的步骤
> 导入jar包
> 创建实体类
> 创建数据库表(hibernate会自动创建)
> 实现映射关系创建配置文件,配置文件的方式
创建位置一般在实体类所在的包中
名称一采用实体类名.hbm.xml
约束文件
“-//Hibernate/Hibernate Mapping DTD 3.0//EN”
“http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd”>
<hibernate-mapping>
<!-- 配置实体类和表的对应 -->
<class name="com.hibernate.entry.User" table="user">
<!-- 配置实体类的id属性,对应于表的id,要求唯一才行 -->
<id type="int" name="id" column="id">
<!-- 设置主键自动增长,有很多值 -->
<generator class="native"></generator>
</id>
<!-- 其他属性的配置 -->
<property name="userName" column="userName"></property>
<property name="password" column="password"></property>
</class>
</hibernate-mapping>
>核心配置文件
位置和名称固定:位置在src下,名字叫hibernate.cfg.xml
约束文件
“-//Hibernate/Hibernate Configuration DTD 3.0//EN”
“http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd”>
<hibernate-configuration>
<session-factory>
<!-- 1.配置数据库信息,必须 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<!-- 2.配置hibernate信息,可选 -->
<!-- 执行的时候输出底层的SQL语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL语句 -->
<property name="hibernate.format_sql">true</property>
<!-- hibernate帮助自动创建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置数据库的方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 3.把映射文件都放到本核心配置文件中,因为hibernate只会加载核心配置文件 -->
<mapping resource="com/hibernate/entry/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
>测试
测试的7个步骤
//1.加载hibernate核心配置文件
//2.创建sessionFactory对象,在此过程中,根据映射关系,创建表
//3.使用sessionFactory创建session对象
//4.开启事务
//5.写具体的curd操作,添加的操作
//6.提交事务
//7.关闭资源
public static void myTest() {
//1.加载hibernate核心配置文件
Configuration cfg=new Configuration();
cfg.configure();
//2.创建sessionFactory对象,在此过程中,根据映射关系,创建表
SessionFactory sessionFactory= cfg.buildSessionFactory();
//3.使用sessionFactory创建session对象
Session session= sessionFactory.openSession();
//4.开启事务
Transaction tx = session.beginTransaction();
//5.写具体的curd操作,添加的操作
User user=new User();
user.setUserName("申");
user.setPassword("123456");
System.out.println(user.getUserName());
session.save(user);
//6.提交事务
tx.commit();
//7.关闭资源
session.close();
sessionFactory.close();
}
执行结果
数据库表创建成功,数据插入成功,小问题是出现了中文问题
四.hibernate深入
1.hibernate的主键生成策略
<!-- 配置实体类的id属性,对应于表的id,要求唯一才行 -->
<id type="int" name="id" column="id">
<!-- 设置主键自动增长,有很多值 -->
<generator class="native"></generator>
</id>
-----------------------------------------------------------------------
生成策略有很多的值:
1.native : 自动选择适合于相应的数据库的主键自动增长方式
2.uuid : 自动生成uuid,32位的16进制字符串
2.hibernate的curd操作
- 增加,调用session.save(user);
//5.写具体的curd操作,添加的操作
User user=new User();
user.setUserName("zhu");
user.setPassword("123456");
System.out.println(user.getUserName());
session.save(user);
- 删除,session.delete(user);
User user = session.get(User.class, 2);
session.delete(user);
- 修改,调用session.update(user);
//5更新操作
User user = session.get(User.class,2);
user.setUserName("shenyuchao");
session.update(user);
System.out.println(user.getId()+":"+user.getUserName()+":"+user.getPassword());
- 查询,调用session.get(User.class,1);
//5 查询事件
User user = session.get(User.class,1);
System.out.println(user.getId()+":"+user.getUserName()+":"+user.getPassword());
3.实体类的状态
- 瞬时态 : 实体类没有id,也跟session没有关联
- 持久态 : 实体类有id,也跟session有关联
- 托管态 : 实体类有id,跟session没有关联
当在以上3中状态中调用session.saveOrUpdate();方法的时候,
瞬时态会执行save,持久态和托管态会执行update
4.hibernate缓存
hibernate的一级缓存
(1)hibernate一级缓存默认打开的
(2)hibernate一级缓存使用的范围是session内,当session关闭就没有了缓存
(3)hibernate一级缓存中的数据必须是持久态的数据
---------------------------------------------------------------------
操作的数据会被缓存到内存中,当进行修改的时候,会操作内存中的数据,然后事务提交的时候,如果数据需要修改,就会更新数据库,如果数据不需要修改就不会更新数据库.
5.hibernate绑定session
(1)在核心配置文件中配置才能使用
<property name="hibernate.current_session_context_class">thread</property>
(2)在程序中调用方法
sessionFactory.getCurrentSession();
(3)curd操作结束则本地线程结束,那么这个session也结束了,不需要手动关闭
6.hibernate的多种查询
- Query对象
使用这个对象不需要写sql语句,但是需要写hql(hibernate query language)语句
SQL换个hql的区别
(1)使用SQL操作的是数据库的表和表的字段
(2)使用hql操作的是实体类和实体类的属性
Query对象的使用
(1)查询所有: from 实体类名称
public static void query() {
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
sessionFactory =Util.getSessionFactory();
session =Util.getSession();
tx=session.beginTransaction();
//Query对象的使用
Query query=session.createQuery("from User");
java.util.List<User> list= query.list();
for (User user:list) {
System.out.println(user);
}
tx.commit();
} catch (Exception e) {
e.printStackTrace();
}
finally{
// session.close();
sessionFactory.close();
}
}
- Criteria对象
Criteria对象不需要写查询语句,直接调用方法即可
public static void criteria() {
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
sessionFactory =Util.getSessionFactory();
session =Util.getSession();
tx=session.beginTransaction();
//**Criteria的使用方法**
Criteria criteria = session.createCriteria(User.class);
List<User> users= criteria.list();
for (User user:users) {
System.out.println(user);
}
tx.commit();
} catch (Exception e) {
e.printStackTrace();
}
finally{
// session.close();
sessionFactory.close();
}
}
- SQLQuery对象
SQLQuery执行的是底层的SQL语句
public static void sqlQuery() {
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
sessionFactory =Util.getSessionFactory();
session =Util.getSession();
tx=session.beginTransaction();
//SQLQuery的使用方法
SQLQuery sqlQuery=session.createSQLQuery("select * from user");
sqlQuery.addEntity(User.class);
List<User> users=sqlQuery.list();
for (User user:users) {
System.out.println(user);
}
tx.commit();
} catch (Exception e) {
e.printStackTrace();
}
finally{
// session.close();
sessionFactory.close();
}
}
7.hibernate的表与表关系的操作
1.表关系
一对多 : 在多的那张表里有一个字段作为外键,这个外键指向一的那张表的主键
多对多 : 生成第三张表,这个表至少包含其他两个表的主键
2.hibernate中1中的思想的实现
- 一对多实现
(1)建立实体类
代码类似,不再演示
(2)让实体类中两方能够互相表示
在一的一方(客户),使用set集合保存多的一方,并建立get和set方法:
private Set<LinkMan> setLinkMans=new HashSet<LinkMan>();
在多的一方,使用一的实体对象来表示,并建立get和set方法:
private Customer customer;
(3)配置文件中做配置,并建立映射关系
在一的一方,配置如下:
<!--name:就是实体类中set的名字-->
<set name="setLinkMans">
<!-- 配置外键,外键是值就是外键的名称 -->
<key column="clid"></key>
<!-- 配置的是联系的那个实体类全路径 -->
<one-to-many class="com.hibernate.entry.LinkMan"/>
</set>
在多的一方,配置如下:
<!-- 配置和customer实体类相联系 ,column是外键名称,两个配置文件中的外键名称一致-->
<many-to-one name="customer" class="com.hibernate.entry.Customer" column="clid"></many-to-one>
- 多对多实现
实现步骤与上面相同,只是配置不同
<!--name指实体类中set集合名称, table指第三张表的名称 -->
<set name="setRoles" table="user_role">
<!-- column指当前映射文件在第三张表中的外键名称 -->
<key column="userid"></key>
<!-- class对应另一个多的全路径,column指这个多在第三张表的外键名称 -->
<many-to-many class="com.hibernate.many2many.Role" column="roleid"></many-to-many>
</set>
-------------------------------------------------------------------------------
<set name="setMUsers" table="user_role">
<key column="roleid"></key>
<many-to-many class="com.hibernate.many2many.MUser" column="userid"></many-to-many>
</set>
</class>
hibernate级联操作
- 一对多级联
(1)级联保存
/*
* 这是一种比较麻烦的方法,
* 建立一的实体类,建立多的实体类,分别表示对方,最后分别保存
*/
public static void save1() {
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
sessionFactory =Util.getSessionFactory();
session =Util.getSession();
tx=session.beginTransaction();
Customer customer=new Customer();
customer.setCname("shen");
customer.setCpassword("123456");
LinkMan linkMan=new LinkMan();
linkMan.setLname("zhu");
linkMan.setLpassword("123456");
//互相表示对方
customer.getSetLinkMans().add(linkMan);
linkMan.setCustomer(customer);
//分别保存
session.save(customer);
session.save(linkMan);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
}
finally{
// session.close();
sessionFactory.close();
}
}
/*
* 这是一种比较简单的写法,需要配置,底层实现还是一样的思想
*/
--------------------------------------------------------------
配置:在一的一方的配置文件中加入级联(cascade="save-update"):
<set name="setLinkMans" cascade="save-update">
--------------------------------------------------------------
Customer customer=new Customer();
customer.setCname("chao");
customer.setCpassword("123456");
LinkMan linkMan=new LinkMan();
linkMan.setLname("ping");
linkMan.setLpassword("123456");
//不用再互相保存对方了,只需要将linkman添加到set中去
customer.getSetLinkMans().add(linkMan);
//不用分别保存了,只需要保存customer
session.save(customer);
(2)级联删除
/*
* 配置了之后,进行级联删除
* 查询然后直接调用delete方法
*/
----------------------------------------------------------------
配置在一的一方:
<set name="setLinkMans" cascade="save-update,delete">
----------------------------------------------------------------
删除代码:
Customer customer=session.get(Customer.class, 2);
session.delete(customer);
(3)级联修改
需求就是把某一个客户的联系人变成另一个客户的联系人
该修改方式有一个弊端,因为hibernate是对外键双向维护的,就造成2次数据库对多的一方的更新,解决的方式是:让一的一方放弃维护外键
<set name="setLinkMans" cascade="save-update,delete" inverse="true">
不需要配置,思想如下:
1.获取目标客户实体对象,
2.获取目标联系人实体对象,
3.将联系人添加到客户,再将客户添加到联系人中
因为这2个实体对象都是持久态的数据,不需要调用session的方法,提交后就会更新数据库
- 多对多级联
(1)多对多级联保存,类似于一对多操作
(2)多对多级联删除,类似于一对多操作
* 多对多维护第三张表 *
对于多对多的操作思想是:将两个多方分别操作,剩下的就是操作第三张表,就能完成功能.比如:
User user=session.get(User.class,2);
Role role=session.get(Role.class,3);
//增加关系
user.getSetRoles().add(role);
//删除关系
user.getSetRoles().remove(role);
五.hibernate的查询
1.对象导航查询,就是查询到一个某一个客户的所有联系人
User user=session.get(User.class,1);
//只需要得到set集合就行,得到的set集合就是想要的结果
Set<LinkMan> linkMans=user.getLinkmans();
2.OID查询,根据id查询方式
根据id查询,上面写过,不写了