MVC和分层架构
- 持久层的设计理念 - DAO = Data Accessor + Active Domain Object
- 业务层的设计理念 - 事务脚本模式(事务的边界在业务层)
- 表示层的架构理念 - MVC架构模式 - 通过控制器(C)实现模型(M)和视图(V)的解耦合
ORM是什么
- ORM映射:Object Relational Mapping(对象关系映射)
- O:面向对象领域的 Object(JavaBean 对象)
- R:关系数据库领域的 Relational(表的结构)
- M:映射 Mapping(XML 的配置文件)
- 如果使用关系型数据库作为持久化方案,那么ORM框架可以帮助我们完成从对象模型到关系模型的双向转换,从而避免繁琐的JDBC模板代码和编写SQL语句
- 最主流的ORM框架是Hibernate和MyBatis
什么时候使用Hibernate - 对应用和数据库设计有完全控制权,不熟悉SQL
什么时候使用MyBatis - 需要高度优化的SQL或存储过程 - 简单一句话:Hibernate 使程序员通过操作对象的方式来操作数据库表记录
Hibernate简介
- Hibernate 是一个开放源代码的对象关系映射(ORM)框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。
- Hibernate 可以应用在任何使用 JDBC 的场合,既可以在 Java 的客户端程序使用,也可以在 Servlet/JSP 的 Web 应用中使用。
- Hibernate 是轻量级 JavaEE 应用的持久层解决方案,是一个关系数据库ORM框架
Hibernate的使用步骤
- 封装业务实体
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
private String password;
private String email;
private Boolean gender;//不使用基本类型
private String tel;
//getter和setter方法
}
在对象关系映射的框架中不要使用基本类型,应该使用包装类型,因为,包装类型的默认值为null,而数据库中的字段为空值时也是null,两两对应。
基本数据类型对应的包装类:int--Interger
byte--Byte
short--Short
long--Long
float--Float
double--Double
char--Character
boolean--Boolean
- 对象关系映射(注解/XML)
//POJO = Plain Ordinary Java Object
//PO = Persistence Object
//POJO + 映射文件/注解 ->PO
@Entity//注解声明该类是Hibernate的持久化类
@Table(name = "t_user")//指定该类映射的表
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id//指定该类的标识属性
@GeneratedValue(strategy = GenerationType.IDENTITY)
//GeneratedValue(generator = "gen")
//GenericGenerator(name = "gen",strategy = "uuid")
@Column(name="userid")
private Integer id;
@Column(unique = true,nullable = false,length = 20)
private String username;
@Column(name="userpass")
private String password;
private String email;
private Boolean gender;//不使用基本类型
@Transient
private String tel;
//getter和setter方法
}
@Entity
:被该注解修饰的POJO就是一个实体。使用该注解可以指定一个name属性,name属性指定该实体类的名称,但大部分无须指定该属性,因为系统默认以该类的类名称作为实体类的名称
@Table
:该注解指定持久化类所映射的表,一般需要指定name属性,即所映射的表名
@id
:指定该类的标识属性。
通常情况下,Hibernate建议为持久化类定义一个标识属性,用于唯一标识某个持久化实例,映射为数据表的主键,如果希望Hibernate自动生成主键值,使用下面这个注解
@GeneratedValue
:属于JPA的注解,支持的属性有:
- strategy:指定主键的生成策略,该属性支持如下4个属性
- GenerationType.AUTO:自动选择最适合底层数据库的书剑生成策略(不推荐使用,在某些情况下会出错)
- GenerationType.IDENTITY:对于MySQL、SQL Server这样的数据库,选择自增长的主键生成策略
- GenerationType.SEQUENCE:对于Oracle这样的数据库,选择使用基于Sequence的主键生成策略
- GenerationType.TABLE:使用辅助表来生成主键
- 如果需要使用Hibernate提供的主键生成策略还需要结合下面这个属性
@GenericGenerator
:支持的属性
- name:必须属性,设置该主键生成器的名称,设置后可在GenerratedValue中指定generator生成器值为该name值,即可使用该主键生成器
- strategy:必须属性。设置该主键生成器的生成策略
- increment:为long、short、int类型主键生成唯一标识,只有在没有其他进程往同一个表中插入数据才能使用,在集群下不要使用
- identity:给提供自增长主键支持的数据表中适用
- sequence:给提供Sequence支持的数据表中适用
- hilo:使用一个高/低位算法高效的生成long、short、int型的标识符
- seqhilo:同上,指定条件有所不同
- uuid:使用UUID算法生成字符串类型的标识符
@Column
:通过该注解可以指定类中的属性所映射的字段的名称,字段长度,唯一约束等等,但是,在实际开发中,都是先创建数据库表再创建持久化类,所以,一般指定列名就可以
@Transient
:在默认情况下,持久化类的所有属性会自动映射到数据表的数据列,如果不想持久化的属性,则使用该注解来修饰
- Hibernate配置文件
默认加载的配置文件hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<!-- 数据库连接属性 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate?useUnicode=true&characterEncoding=utf8</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<!-- SQL方言 -->
<!-- 如果使用MySQL5.7及以上版本配置MySQL57Dialect -->
<!-- 如果使用MySQL5.7及以下版本配置MySQL5InnoDBDialect -->
<!-- 如果使用Hibernate5.2.9以前的版本直接配置MySQLDialect -->
<!-- ThreadLocal -->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- MySQL数据库底层有多种存储引擎 -->
<!-- InnoDB/MyISAM/Memory -->
<!-- 设置当前会话和当前线程进行绑定 -->
<!-- 每个线程都持有自己的资源不会因为竞争资源影响并发 -->
<!-- 不会重复创建Session造成资源的浪费以及无法开启事务环境 -->
<property name="current_session_context_class">thread</property>
<!-- 显示并格式化SQL语句(在上线版本中要去掉这两个配置),影响性能 -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!-- 对象关系映射引用 -->
<mapping class="com.chenx.hib02.domain.User"/>
</session-factory>
</hibernate-configuration>
- 核心API的使用
编写测试类
public class AppTest{
private static SessionFactory sessionFactory;
private Session session;
@BeforeClass //在所有的测试方法执行之前只执行一次得方法
public static void setUpBeforeClass(){
sessionFactory = new Configuration().configure().buildSessionFactory();
}
@AfterClass //在所有的测试方法执行结束后只执行一次得方法
public static void tearDownAfterClass(){
sessionFactory.close();
}
@Before //每个测试方法执行之前都要先执行的方法
public void foo(){
session = sessionFactory.getCurrentSession();
session.beginTransaction();
}
@After //每个测试方法执行之后都要执行该方法
public void bar(){
session.getTransaction().commit();
session.close();
}
@Test
public void testSave(){
User user = new User();
user.setUsername("陈其");
user.setPassword("741852");
user.setGender(false);
user.setEmail("wrw@qq.com");
Assert.assertNotNull(session.save(user));
}
@Test
public void testGet(){
User user = session.get(User.class, "陈其");
Assert.assertEquals("陈其", user.getUsername());
Assert.assertEquals("wrw@qq.com", user.getEmail());
Assert.assertEquals("741852", user.getPassword());
Assert.assertEquals(false, user.getGender());
}
}
Configuration
:每个Hibernate的配置文件对应一个Configuration对象,new Configuration().configure()负责加载hibernate.cfg.xml文件
SessionFactory
:new Configuration().configure().buildSessionFactory()该方法产生一个不可变的SessionFactory对象,该对象很消耗资源,所以一般一个数据库对应一个SessionFactory
Session
:通过SessionFactory对象.openSessioon(),或许.getCurrentSession()可以得到一个Session实例,推荐使用getCurrentSession,1.因为getCurrentSession创建的session会和绑定到当前线程,而openSession不会。2.getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭。
这里getCurrentSession本地事务(本地事务:jdbc)时要在配置文件里进行如下设置:
<property name="current_session_context_class">thread</property>
Session对象的几个重要方法:
- 持久化对象状态的方法
- save:将对象转化为持久化状态,该对象的属性将被保存到数据库,该方法需要立即返回持久化对象的标识属性值,所以执行save方法时立即将持久化对象对应的数据插入数据库
- persist:将对象转化为持久化状态,该对象的属性将被保存到数据库
与save方法的区别是,当它在一个事务外部被调用时,并不立即转换成insert语句。这个功能很有用,尤其是需要封装长会话流程时。
- 根据主键加载持久化实体
- get():根据主键加载持久化实例,但get()方法会立刻访问数据库,如果没有记录返回null
- load():根据主键加载持久化实例,如果没有匹配到数据库记录,load()方法抛出HibernateException异常,如果在持久化注解中指定了延迟加载,则load方法会返回一个未初始化的代理对象(持久化对象的替身),这个代理对象并没有加载数据记录,直到程序去调用该代理对象的某个方法是,Hibernate才会去访问数据库(如果希望在某个对象中创建一个指向另一个对象的关联,又不想在数据库中装载该对象的同时立即装载相关联的全部对象,延迟加载方式就非常有用了)
- 更新持久化实体
Hibernate中对象有三种状态:1.瞬时态(刚创建的对象,尚未与Session关联,不会持久化到数据库,也不会被赋予持久化标识,有机会被垃圾回收)2.持久态(对象在数据库中有对应的记录,并拥有持久化标识,与Session关联,对象状态的改变会被写回数据库,无法垃圾回收)3.游离态(曾经处于持久态,但是因为Session关闭或者对象从Session中移除变成与Session失去关联,有机会被垃圾回收)- 更新处于持久化状态的对象时,直接调用该对象的属性set方法即可更新数据库,Hibernate会自动发出数据库更新语句
- 更新一个游离态的对象时通过update()、updateOrSave()方法来保存这些修改,使用这两个方法后对象由游离态再次回到持久态
- 删除持久化实体
- 通过delete()方法来删除持久化实例,对象从持久态变为瞬时态(删除态)
网友评论