1 持久层开发的问题
随着互联网技术的发展,现在的企业开发中用到的用于数据存储的产品,不再仅仅是关系型数据库,而是要根据场景需要选择不同的存储技术,比如用于缓存热点数据的redis,用于存储文档数据的mongodb,用于支持强大搜索功能的elasticsearch等等。
在Java中,对于上面所说的产品都提供了优秀的访问技术。比如针对关系型数据库的mybatis、jpa等技术,针对于redis的jedis技术等等… 这些技术虽然可以很好的针对各个存储产品进行访问操作,但同时也带来了新的问题,那就是不同的持久层技术的API是不一样的。
这样一来,开发人员就必须同时掌握多种数据访问技术,这无疑增加了开发成本。那么我们会想,有没有这样一种技术,它可以使用一套API支持各个不同的存储的访问呢?就在这样的需求下,SpringData产生了。
1 SpringData简介
2.1 什么是SpringData
SpringData是一个用来简化dao层开发的框架。它在保证了各个底层存储特性的同时,提供了一套统一的数据访问API。它可以很好的支持常用的关系型数据库和非关系型数据库。
使用SpringData作为dao层开发技术,将大大简化代码量,而且其API比各个技术的原生API更加简单易用。
2.2 SpringData的主要模块
SpringData支持的持久层技术非常多,我们只介绍几个常见的:
- Spring Data common SpringData的核心模块,定义了SpringData的核心功能
- Spring Data JDBC 对JDBC的Spring Data存储库支持
- Spring Data JPA 对JPA的Spring Data存储库支持
- Spring Data MongoDB 对MongoDB的基于Spring对象文档的存储库支持
- Spring Data Redis 封装Jedis技术,对redis实现访问操作
- Spring Data Elasticsearch 对Elasticsearch实现访问操作
3 JPA基础
Hibernate是一个全自动的ORM框架,是对 JDBC技术的封装。它在实体类和数据库表之间建立了映射关系,使得程序员可以使用面向对象编程思维来操纵数据库,而Hibernate会自动给我们生成 SQL 语句。
JPA 的全称是 Java Persistence API,即 Java 持久化 API,是 SUN 公司推出的一套基于 ORM 的规范,注意不是 ORM 框架——因为 JPA 并未提供 ORM 实现,它只是提供了一些编程的 API 接口。
4 JPA实战
4.1 目标
本章节我们是实现的功能是搭建Jpa环境,并实现一条数据的增删改查。
4.2 准备数据库环境
--准备数据库,创建一张文章表备用 CREATE TABLE `article` ( `aid` int(11) NOT NULL auto_increment COMMENT '主键', `author` varchar(255) default NULL COMMENT '作者', `createTime` datetime default NULL COMMENT '创建时间', `title` varchar(255) default NULL COMMENT '标题', PRIMARY KEY (`aid`) );
4.3 创建java工程,导入坐标
<dependencies> <!--Jpa的支撑框架hibernate--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>5.0.7.Final</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <!-- 日志 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <!-- 单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
4.4 创建实体类
public class Article implements Serializable { private Integer aid; private String title; private String author; private Date createTime; //省略set和get方法。。。 //省略toString方法。。。 }
4.5在实体类中配置映射关系
@Entity//表示这是一个实体类 @Table(name = "article") //建立实体类和表的映射关系 public class Article implements Serializable { @Id//声明当前私有属性为主键 @GeneratedValue(strategy = GenerationType.IDENTITY) //配置主键的生成策略 private Integer aid; //声明类的属性跟数据表字段的对应关系,如果属性名称和字段名称一致,可省略 @Column(name = "title") private String title; private String author; private Date createTime; }
4.6 加入 JPA 的核心配置文件
在maven工程的resources路径下创建一个名为META-INF的文件夹,在文件夹下创建一个名为persistence.xml的配置文件。注意: META-INF文件夹名称不能修改,persistence.xml文件名称不能改。 <?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <!--持久化单元--> <persistence-unit name="springdata" transaction-type="RESOURCE_LOCAL"> <!--配置 JPA 规范的服务提供商 --> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <properties> <!-- 数据库驱动 --> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <!-- 数据库地址 --> <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///springdata"/> <!-- 数据库用户名 --> <property name="javax.persistence.jdbc.user" value="root"/> <!-- 数据库密码 --> <property name="javax.persistence.jdbc.password" value="adminadmin"/> <!--jpa的核心配置中兼容hibernate的配置--> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> <property name="hibernate.hbm2ddl.auto" value="update"/> </properties> </persistence-unit> </persistence>
4.7 测试
4.7.1 实现保存操作
@Test public void testSave() { //1 创建持久化管理器工厂 EntityManagerFactory factory = Persistence.createEntityManagerFactory("springdata"); //2 创建持久化管理器 EntityManager entityManager = factory.createEntityManager(); //3 获取事务,并开启 EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); //4 操作 Article article = new Article(); article.setTitle("测试文章"); article.setAuthor("oldlu"); article.setCreateTime(new Date()); entityManager.persist(article); //5 事务提交 transaction.commit(); //6 关闭资源 entityManager.close(); }
4.7.2 实现查询操作
@Test public void testFindByAid() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("springdata"); EntityManager entityManager = factory.createEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); Article article = entityManager.find(Article.class, 1); System.out.println(article); transaction.commit(); entityManager.close(); }
4.7.3 实现修改操作
@Test public void testUpdate() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("springdata"); EntityManager entityManager = factory.createEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); Article article = entityManager.find(Article.class, 1); //修改 article.setAuthor("oldlu程序员"); transaction.commit(); entityManager.close(); }
4.7.4 实现删除操作
@Test public void testDelete() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("springdata"); EntityManager entityManager = factory.createEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); Article article = entityManager.find(Article.class, 1); //删除 entityManager.remove(article); transaction.commit(); entityManager.close(); }
5 JPA的重要API介绍
5.1 EntityManagerFactory
EntityManagerFactory接口主要用来创建EntityManager实例 EntityManagerFactory是一个线程安全的对象,并且其创建极其浪费资源,所以编程的时候要保持它是单例的。
5.2 EntityManager
在JPA规范中,EntityManager是操作数据库的重要API,他是线程不安全的,需要保持线程独有。 重要方法说明: getTransaction: 获取事务对象 persist:保存操作 merge:更新操作 remove:删除操作 find/getReference:根据id查询
5.3 save和saveAndFlush方法区别
On saveAndFlush, changes will be flushed to DB immediately in this command. With save, this is not necessarily true, and might stay just in memory, until flush or commit commands are issued.
在saveAndFlush上,此命令中的更改将立即刷新到DB。使用save,就不一定了,它可能只暂时保留在内存中,直到发出flush或commit命令。
But be aware, that even if you flush the changes in transaction and do not commit them, the changes still won’t be visible to the outside transactions until the commit in this transaction.
但是要注意的是,即使在事务中刷新了更改并且未提交它们,这些更改对于外部事务仍然不可见,直到,提交这个事务。
In your case, you probably use some sort of transactions mechanism, which issues commit command for you if everything works out fine.
在您的情况下,您可能使用某种事务机制,如果一切正常,它会为您发出commit命令。
5.3.1 总结
比如在我们得项目中,保存一条数据后,我又想立马用到这条数据得id,因为实体类是配置了uuid自动生成,所以使用saveAndFlush()方法就可以立即获取到这条数据得id。但是如果用sava()方法,你不flush()或者commit,你得数据是暂时只在内存中保存,所以此时这条数据是没有主键id的.
提交事务后数据插入进数据库,要想在事务提交之前避免缓存插入数据库需要在执行完save操作调用flush方法或者直接执行saveAndFlush方法即可
6 SpringData JPA简介
SpringData JPA是Spring Data家族的一个成员,是Spring Data对JPA封装之后的产物,目的在于简化基于JPA的数据访问技术。使用SpringData JPA技术之后,开发者只需要声明Dao层的接口,不必再写实现类或其它代码,剩下的一切交给SpringData JPA来搞定 。