一、Java数据持久化方案
1:JDBC
JDBC是Java语言访问数据库的一种规范,是一套API。JDBC (Java Database Connectivity) API,即Java数据库编程接口,是一组标准的Java语言中的接口和类,使用这些接口和类,Java客户端程序可以访问各种不同类型的数据库。
JDBC规范采用接口和实现分离的思想设计了Java数据库编程的框架。接口包含在java.sql及javax.sql包中,其中java.sql属于JavaSE,javax.sql属于JavaEE。
JDBC访问数据库的步骤:
1.得到数据库驱动程序
2.创建数据库连接
3.执行SQL语句
4.得到结果集
5.对结果集做相应的处理(增,删,改,查)
6.关闭资源:这里释放的是DB中的资源文链接
2:JdbcTemplate
JdbcTemplate是spring框架提供的替代原生JDBC的类。它是对JDBC的一种封装,抽象我们常用的一些方法。
JdbcTemplate主要提供以下五类方法:
1)execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
2)update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;
3)query方法及queryForXXX方法:用于执行查询相关语句;
4)call方法:用于执行存储过程、函数相关语句。
3:ORM
ORM 是Object-Relation-Mapping,即对象关系影射技术,是对象持久化的核心。ORM是对JDBC的封装,从而解决了JDBC的各种存在问题。
ORM则建立了Java对象与数据库对象之间的影射关系,程序员不需要编写复杂的SQL语句,直接操作Java对象即可,从而大大降低了代码量,也使程序员更加专注于业务逻辑的实现。
使用ORM技术,可以将数据库层完全隐蔽,呈献给程序员的只有Java的对象,程序员只需要根据业务逻辑的需要调用Java对象的Getter和 Setter方法,即可实现对后台数据库的操作,程序员不必知道后台采用什么数据库、有哪些表、有什么字段、表与表之间有什么关系。
目录最流行的ORM框架:Hibernate,MyBatis。
二、Hibernate概述
Hibernate是开源的一个ORM(对象关系映射)框架。ORM是一种思想,Hibernate是实现了ORM思想的java持久层ORM框架。Hibernate本身是基于JDBC,对JDBC访问数据库做了抽象和封装.所以它是需要数据库的驱动包.
它的作用就是在关系型数据库和对象之间做了一个映射。从对象(Object)映射到关系(Relation),再从关系映射到对象。这样,我们在操作数据库的时候,不需要再去和复杂SQL打交道,只要像操作对象一样操作它就可以了
Hibernate六大核心接口,两个主要配置文件,以及他们直接的关系。Hibernate的所有内容都在这了。那我们从上到下简单的认识一下,每个接口进行一句话总结。
1、Configuration接口:负责配置并启动Hibernate
2、SessionFactory接口:负责初始化Hibernate
3、Session接口:负责持久化对象的CRUD操作
4、Transaction接口:负责事务
5、Query接口和Criteria接口:负责执行各种数据库查询
注意:Configuration实例是一个启动期间的对象,一旦SessionFactory创建完成它就被丢弃了。
1)下载Hibernate
2)安装
下载解压后,Hibernate5.4 有18个必须jar包。将其复制到项目中,再创建build path。
3)配置
配置文件在hibernate-release-5.4.0.Final\project\etc目录中:
1:Hibernate主配置文件(hibernate.cfg.xml):关联约束文件hibernate-configuration-3.0.dtd.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 1.数据库配置 -->
<!-- 1.1.连接数据库的驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<!-- 1.2.连接数据库的地址,路径 -->
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hbm?serverTimezone=GMT%2B8</property>
<!-- 1.3.连接数据库的用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 1.4.连接数据库的密码 -->
<property name="hibernate.connection.password">root</property>
<!-- 1.5.数据库方言配置根据不同的方言生成符合当前数据库语法的sql -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 2.其它配置 -->
<!-- 2.1.在控制台打印sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 2.2.打印sql语句前,会将sql语句先格式化 -->
<property name="hibernate.format_sql">true</property>
<!-- 2.3.自动建表 -->
<!-- <property name="hibernate.hbm2ddl.auto">create</property> -->
<!-- 2.4.事务自动提交 -->
<property name="hibernate.connection.autocommit">true</property>
<!-- 2.5.将Session与线程绑定=> 只有配置了该配置,才能使用getCurrentSession -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 3.加载ORM映射文件-->
<mapping resource="com/openbox/domain/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
2:hibernate.properties文件,找到连接数据库的基本要素.
## MySQL
#hibernate.dialect org.hibernate.dialect.MySQLDialect
#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
#hibernate.connection.driver_class com.mysql.jdbc.Driver
#hibernate.connection.url jdbc:mysql:///test
#hibernate.connection.username gavin
#hibernate.connection.password
3:对象与数据表映射文件user.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">
<!-- User对象的映射文件 -->
<hibernate-mapping package="com.openbox.domain">
<class name="User" table="t_user">
<id name="id" column="uid">
<generator class="native"/>
</id>
<property name="username" column="uname" />
</class>
</hibernate-mapping>
三、Hibernate实现CRUD操作
1):创建数据库hbm,再建表
CREATE TABLE `t_user` (
`uid` bigint(20) NOT NULL AUTO_INCREMENT,
`uname` varchar(20) DEFAULT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8
2):创建User对象User.java
package com.openbox.domain;
public class User {
private Long id;
private String username;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + "]";
}
}
3):创建User的DAO接口及其实现类
IUserDAO.java
package com.openbox.dao;
import java.util.List;
import com.openbox.domain.User;
public interface IUserDAO {
//定义User对象操作增删改查的接口
void save(User u);
void update(User u);
void delete(User u);
User get(Long id);
List<User> list();
}
UserDAOImpl.java
package com.openbox.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import com.openbox.domain.User;
public class UserDAOImpl implements IUserDAO {
//-----------DML操作----------------//
@Override
public void save(User u) {
//1.创建配置对象
Configuration cfg = new Configuration();
//2.读取配置文件
cfg.configure("/hibernate.cfg.xml");
//3.创建SessionFactory
SessionFactory buildSessionFactory = cfg.buildSessionFactory();
//4.获取Session
Session openSession = buildSessionFactory.openSession();
//5.打开事务(设置事务活动状态)
openSession.beginTransaction();
//6.DML操作
openSession.save(u);
//7.提交/回滚事务
openSession.getTransaction().commit();
//8.关闭Session
openSession.close();
//9.关闭SessionFactory
buildSessionFactory.close();
}
@Override
public void update(User u) {
//1.创建配置对象
Configuration cfg = new Configuration();
//2.读取配置文件
cfg.configure("/hibernate.cfg.xml");
//3.创建SessionFactory
SessionFactory buildSessionFactory = cfg.buildSessionFactory();
//4.获取Session
Session openSession = buildSessionFactory.openSession();
//5.打开事务(设置事务活动状态)
openSession.beginTransaction();
//6.DML操作
openSession.update(u);
//7.提交/回滚事务
openSession.getTransaction().commit();
//8.关闭Session
openSession.close();
//9.关闭SessionFactory
buildSessionFactory.close();
}
@Override
public void delete(User u) {
//1.创建配置对象
Configuration cfg = new Configuration();
//2.读取配置文件
cfg.configure("/hibernate.cfg.xml");
//3.创建SessionFactory
SessionFactory buildSessionFactory = cfg.buildSessionFactory();
//4.获取Session
Session openSession = buildSessionFactory.openSession();
//5.打开事务(设置事务活动状态)
openSession.beginTransaction();
//6.DML操作
openSession.delete(u);
//7.提交/回滚事务
openSession.getTransaction().commit();
//8.关闭Session
openSession.close();
//9.关闭SessionFactory
buildSessionFactory.close();
}
//-----------DQL操作----------------//
@Override
public User get(Long id) {
//1.创建配置对象
Configuration cfg = new Configuration();
//2.读取配置文件
cfg.configure("/hibernate.cfg.xml");
//3.创建SessionFactory
SessionFactory buildSessionFactory = cfg.buildSessionFactory();
//4.获取Session
Session openSession = buildSessionFactory.openSession();
//5.具体的查询操作
User user = (User) openSession.get(User.class, id);
//6.关闭Session
openSession.close();
//7.关闭SessionFactory
buildSessionFactory.close();
System.out.println(user);
return user;
}
@Override
public List<User> list() {
//1.创建配置对象
Configuration cfg = new Configuration();
//2.读取配置文件
cfg.configure("/hibernate.cfg.xml");
//3.创建SessionFactory
SessionFactory buildSessionFactory = cfg.buildSessionFactory();
//4.获取Session
Session openSession = buildSessionFactory.openSession();
//5.具体的查询操作,使用HQL语句
Query query = openSession.createQuery("select u from User u");
List<User> list = query.list();
//6.关闭Session
openSession.close();
//7.关闭SessionFactory
buildSessionFactory.close();
return list;
}
}
4):用JUnit5创建测试类UserTests.java
package com.openbox.test;
import java.util.List;
import org.junit.jupiter.api.Test;
import com.openbox.dao.IUserDAO;
import com.openbox.dao.UserDAOImpl;
import com.openbox.domain.User;
public class UserTests {
private IUserDAO dao = new UserDAOImpl();
@Test
public void testSave() {
User user=new User();
user.setUsername("jack");
dao.save(user);
}
@Test
public void testUpdate() {
User user=dao.get(5L);
user.setUsername("MOMO");
dao.update(user);
}
@Test
public void testDelete() {
User user=dao.get(2L);
dao.delete(user);
}
@Test
public void testGet() {
User user = dao.get(1L);
System.out.println(user);
}
@Test
public void testList() {
List<User> users=dao.list();
for (User user : users) {
System.out.println(user);
}
}
}
5):操作结果
5):常见错误
1).操作数据库,必须拷贝数据库对于的驱动包.
2).hibernate.cfg.xml中的<property>配置不能出现空格,如:<property name="hibernate.connection.username ">root</property>
3).忘记调用configure()方法,正确写法:Configuration cfg = new Configuration().configure(); //加载hibernate.cfg.xml文件.
4).org.hibernate.PropertyNotFoundException: 找不到对象中指定的属性名.(属性property有getter/setter决定,而不是字段Field决定)
5).SessionException : Session is closed:不能再关闭Session之后,使用Session对象.
6).实体类存在无参数构造器.
7).Hibernate并不要求持久化类必须实现java.io.Serializable接口,但对于RMI或JavaEE分布式结构的Java应用,必须实现该接口.Hibernate要求持久化类,必须提供一个不带参数的构造器.
四、Hibernate配置细节
1)自动生成数据库表
在Hibernate主配置文件(hibernate.cfg.xml)中,有以下配置参数:
根据对象和映射文件,在创建SessionFactory的时候,可以生成对应(交给Hibernate管理的映射文件)的数据表:
hibernate.hbm2ddl.auto=create-drop:删除并创建表,关闭SessionFactory时,删除数据库表.
hibernate.hbm2ddl.auto=create:删除并创建表 平时上课,测试
hibernate.hbm2ddl.auto=update:更新表结构:开发项目过程中:
hibernate.hbm2ddl.auto=validate:验证表结构:如果表结构和映射文件不匹配,hibernate启动失败
1):create-drop
1,删除那些表?创建那些表:删除本次hibernate管理的对象对应的表;创建hibernate本次管理的对象对应的表;
2,如果新加一个domain会怎么处理:创建对应的表;
3,如果删除一个domain会怎么处理:不管;
4,一定要正常关闭SessionFactory,才会正常删除表;
5,使用:一般不会使用create-drop;
----------------------------------------------
2):create
1,删除那些表?创建那些表:删除本次hibernate管理的对象对应的表;创建hibernate本次管理的对象对应的表;
2,如果新加一个domain会怎么处理:创建对应的表;
3,如果删除一个domain会怎么处理:不管;
使用:
4,一般在做测试的时候使用create方法;
5,因为每次都是删除表并重新创建表;所以可以保证多次测试的代码不用重写;
6,注意在黑盒测试的时候不能使用create;
-----------------------------------------------
3):update
1,检查并修改那些表?修改本次hibernate管理的表;
2,如果表已经存在,怎么处理?检查表结构和当前对象结构是否匹配,如果不匹配,尝试更新当前表结构;
3,如果表不存在,怎么处理:创建新表;
4,如果对象的结构有变化,怎么更新
1,添加一个属性:在表中添加一列;
2,删除一个属性:不管;
3,修改一个属性:尝试修改属性对应的列类型,如果不能修改,抛出警告;
使用:
1,在黑盒测试的时候使用update;
2,在生产环境不建议使用update(运营过程中);
3,在启动的时候一定要关注由update导致的更新表结构失败;
4):validate:
检查当前hibernate管理的对象对应的表和数据库的表结构是否匹配,如果有任何不匹配,直接报错,hibernate启动失败;
在生产环境中一般使用vaildate,保证当前数据库表版本和hibernate当前对象版本匹配;
2):映射文件细节User.hbm.xml
1.package是可以不写的,如果不写package,其中所有的类都必须有全限定名.
2.在一个hbm.xml中,可以写多个对象的映射,但是一般来说,一个映射文件对应一个实体对象.建议和类名相同(User.java --> User.hbm.xml)
3.class元素的table属性是可以省略的,如果不写table,对应table的名称和类的名称一模一样(大小写一样).
4.property元素对应的是对象的属性:fullName
什么是属性:由一对符合命名规范的getter和setter构成的;hibernate找的是getter和setter
hibernate什么时候使用getter:把对象-->数据库列中,getter方法返回的内容就是要保存到数据库中的内容
hibernate什么时候使用setter:数据库列-->对象中,setter方法传入的值就是数据库中的值
hibernate不关心getter和setter方法的可见性
5.可以通过修改property元素的access属性来改变访问策略(访问属性/字段).<property name="bornDate" access="field"/>:使用字段来关联表字段
6.property元素的type属性可以为对象的属性添加指定的映射类型
type里面写的类型,不是数据库的类型,是hibernate定义的一种中间类型,
JAVA类型-中间类型-数据表类型
7.为列添加更多的额外控制
在property元素的子元素column中,可以添加更多的列的控制条件
8.控制属性的可变性:
insert属性决定该列是否出现在INSERT语句中:<property name="" insert = "true">:
有值就出现在SQL语句,没有值就不出现:<class name="User" dynamic-insert="true">
9.auto-import:自动导入,hibernate为其中的对象自动的起一个别名(默认就是类的名称,用于查询封装VO对象)
<hibernate-mapping auto-import="false">
<!-- 自己为类起别名 -->
<import class="com._520it.day1._03_config.Person" rename="Person2"/>