===============================================================================================
spring boot搭建项目后,想要数据进行持久化操作,更进一步的完善项目的话,就要使用到一个具体的ORM了。而spring boot中完美的支持了spring-data-jpa。
这一篇就使用spring-data-jpa进行入门的数据持久化处理
===============================================================================================
本篇数据库使用mysql,所以pom加入依赖需要两个
org.springframework.boot spring-boot-starter-data-jpa mysql mysql-connector-java
结构如下:
【entity与domain,dao与repository的区别是什么,看附录2】
配置文件application.properties
【在首次启动之后,将spring.jpa.hibernate.ddl-auto=create 修改为spring.jpa.hibernate.ddl-auto=update,以免下次启动重新创建所有的数据表】
【或者 直接将值设置为update,也是可以实现首次创建表,且之后实体字段变化或新增实体,都会自动在数据库中更新且不会删除原来的表和数据,所以建议直接使用update,但是不会打印创建表的sql语句】
【】
#viewspring.mvc.view.prefix = /WEB-INF/views/spring.mvc.view.suffix = .jsp#datasourcespring.datasource.continue-on-error=false spring.datasource.url=jdbc:mysql://localhost:3306/orderdiscountspring.datasource.username=rootspring.datasource.password=rootspring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.jpa.database=mysqlspring.jpa.show-sql=truespring.jpa.hibernate.ddl-auto=updatespring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
日志配置文件 logback-spring.xml
【】
logback INFO true %black(控制台-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger) - %cyan(%msg%n) UTF-8 ${LOG_HOME}logback.%d{yyyy-MM-dd-HH-mm}[%i].log 10kb 30 1GB 文件记录-%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger - %msg%n UTF-8
要想和数据库打交道,这里还是关系型数据库,那就来个实体和数据库的表对应起来
实体User.java
package com.sxd.entity;import org.hibernate.annotations.GenericGenerator;import javax.persistence.*;@Entity@GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator" )public class User { private String id; private String username; private String password; private Integer age; @Id @GeneratedValue(generator = "uuid2") public String getId() { return id; } public void setId(String id) { this.id = id; } @Column(nullable = false) public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Column(nullable = false) public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Column(nullable = false) public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public User() { } public User(String id, String username, String password, Integer age) { this.id = id; this.username = username; this.password = password; this.age = age; }}
spring-data-jpa的优势体现就是下面这个接口啦!!
【】
Dao层放在repository目录下 接口UserRepository.java
package com.sxd.repository;import com.sxd.entity.User;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.jpa.repository.Query;import org.springframework.data.repository.query.Param;public interface UserRepository extends JpaRepository{ User findByUsername(String username); User findByUsernameAndPassword(String username,String password); User findById(String id); @Query("select u from User u where u.username = :name") User findUser(@Param("name")String username); User findTop3ByAge(Integer age);}
就这么几步,就能进行数据的持久化操作了。
启动创建数据表如下,执行的sql语句如下:
【如果spring.jpa.hibernate.ddl-auto=update,也会创建数据表,但是不会有SQL语句打印出来】
好了建立一个单元测试类,使用一下自己写的Repository层的方法和已经封装好的一些方法:
JunitTest.java是放在test目录下的
package com.sxd.logexample;import com.sxd.LogExampleApplication;import com.sxd.entity.User;import com.sxd.repository.UserRepository;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.List;import java.util.Objects;import java.util.UUID;@RunWith(SpringJUnit4ClassRunner.class)@SpringBootTest(classes = LogExampleApplication.class)public class JunitTest { @Autowired private UserRepository userRepository; @Test public void dealUser(){ //插入新的数据 for (int i = 0; i < 10; i++) { User user = new User(); user.setId(UUID.randomUUID().toString()); user.setUsername("用户名"+i); user.setPassword("123"+i); user.setAge(i+1); userRepository.saveAndFlush(user); } //根据ID查询// User user = userRepository.findById("03d99bf3-a171-4986-a75f-92cadc3aa75b");// System.out.println(user);//重写了user的toString()方法即可打印出 //根据userRepository中自写方法查询// User user = userRepository.findByUsernameAndPassword("用户名1","1231");// System.out.println(user); //查询所有// Listlist = userRepository.findAll();// if(Objects.nonNull(list)){// list.forEach(i->{// System.out.println(i);// });// } //删除所有 userRepository.deleteAll(); }}
然后右键在单元测试方法上 运行起来即可。【】
执行完sava方法之后,就会执行插入,sql语句如下:
数据库中也插入成功:
下面的方法 自己一个一个测试即可。
==========================================结束语====================================================
这章就是简单的使用spring-data-jpa进行和数据库交互的操作。数据持久化得以实现,那就解决了项目一个很重大的问题了。但这里只是最最开始的一些,后面会把spring-data-jpa的复杂使用解开面纱。
===========================================附录1:===================================================
如果有人对spring-data-jpa和hibernate是什么关系存在疑问,可以看看这部分:
①JPA首先得介绍一下,他只是一套规范和标准,也就是一堆堆的接口,并未实现;
②hibernate是对JPA的一种实现,就是你具体执行持久化操作调用的方法内具体干了什么,都是Hibernate实现的;
③spring-data-jpa则是对hibernate实行了再封装,大大的简化了原本DAO层的实现,也就是现在的repository层。因为本章就是用的spring-data-jpa,如果你之前使用的是三大框架还是什么巴拉巴拉之类的,肯定是上去先把项目的目录框架,entity,dao,daoimpl,service,serviceimpl,controller层搭建好,才开发的。
④spring spring-boot官方对hibernate是一直都有支持的,而对mybatis则没有,但并不代表它不能与mybatis集成。【这点有点废话,但是却是想表达】
===========================================附录2:===================================================
参考自:http://blog.sina.com.cn/s/blog_93df03f20102vwpm.html
entity:和数据库数据表绝对对应的实体,放在entity下
model:前台需要是什么,model就被处理成什么
domain:代表一个对象模块。
分开来说:
①entity【实体】习惯性使用这个,作为实体的包名。entity中有几个属性,对应的数据表中就有几个字段。并且字段类型都保持绝对一致。
②model【模型】的使用,例如User对象实体中有十个字段,但是前台仅需要username和age的话,那把整个实体传给前台无疑多传输了好些无用的数据。又比如User的sex字段,数据库中存储为男的1,女的2。如果把User对象传给前台,前台js还需要判断一下,而如果sex存储改变了,2为男,1为女,这样js还需要进行改动。所以可以将前台需要的数据封装为model传给前台。而model对象都放在model包下。
③domain【域】是一个订单,一个用户信息等概念的划分。比如一个招聘网站的项目,最重要的对象就是简历了,那么简历是怎么存到数据库的呢,不可能用一张表就能存的,因为简历包含基本信息和工作经验,项目经验,学习经验等。基本信息可以存在简历表,但是涉及到多条的就不行,因为没人知道有多少条工作经验,项目经验,所以必须要单独建工作经验表和项目经验表关联到简历基本信息表。但是前台页面是不关心这些的,前台需要的数据就是一个简历所有信息,这时就可以用到domain来处理,domain里面的类就是一个简历对象,包含了简历基本信息以及list的工作经验,项目经验等。这样前端只需要获取一个对象就行了,不需要同时即要获取基本信息,还要从基本信息里面获取工作经验关联的简历编号,然后再去获取对应的工作经验了。
===========================================附录3:关于自定义简单查询的说明=================================================
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
根据方法名自己生成的sql语句
====================================================================================================================