当前位置: 澳门新濠3559 > 编程 > 正文

data jpa用起来就很简单,每个实体实例对应该表中

时间:2019-10-06 23:51来源:编程
数据持久化的操作,一般都要由我们自己一步步的去编程实现,mybatis通过我们编写xml实现,hibernate也要配置对应的xml然后通过创建session执行crud操作。那么有没有这样一种技术,就是把

数据持久化的操作,一般都要由我们自己一步步的去编程实现,mybatis通过我们编写xml实现,hibernate也要配置对应的xml然后通过创建session执行crud操作。那么有没有这样一种技术,就是把底层的这些crud操作都封装好了,我们直接调用方法就行了,答案是有的,通过springData Jpa 就可以实现。点我可下载本案例源码。

在spring boot的项目中使用spring data jpa真的很简单,写起来真的是笔下生风,神清气爽。非常适合喜欢偷懒的人,可以让你抛开反复编写的dao层代码以及一些写吐了的简单查询语句。首先spring data jpa用起来就很简单,再加上集成在spring boot的项目中,还省去了xml配置,就更是开箱即用了。

 spring-data-jpa官方使用说明文档:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

  这一节的内容比较简单,是springboot和jpa的简单整合,jpa默认使用hibernate,所以本质就是springboot和hibernate的整合。

springData,显然也是spring家族的,data,顾名思义,它就是操作数据的一个框架。jpa,全称为Java persistence api,是用来管理java ee 或Java se环境中的持久化、以及对象关系映射的api,hibernate就是它的一个实现。当jpa遇上springData,就是见证奇迹的时候!它们俩在一起,dao层我们基本上无需再写代码,只需定义接口就可以了,一般的实现都不用我们写了,我们只需调用即可。

首先jpa(Java Persistence API)是一种orm框架的规范,让一个实体类自身就可以通过注解描述其与数据库表的对应关系。jpa只是一个接口规范,用的最多的实现是hibernate。而spring data jpa就是采用hibernate作为实现的基础上,又进行的一层封装,更加屏蔽掉了hibernate的使用细节,降低了学习门槛。

 spring-data-jpa的使用说明:https://www.cnblogs.com/WangJinYang/p/4257383.html

  说实话,听别人都说spring data jpa很简化操作,不用写多少代码,今天我们就来看看。

1、实体:实体表示关系数据库中的表,每个实体实例对应该表中的一条记录,实体类应该有标识其为实体的注解,还应该有唯一的对象标识符,简单主键或复合主键。

1.基本配置要使用spring data jpa需要在pom.xml种添加一个依赖:

spring-data-jpa API地址:https://docs.spring.io/spring-data/data-jpa/docs/current/api/

  顺便一提的是,传统大公司用hibernate比较多,互联网公司用mybatis比较多。

2、关系:关系无外乎一下几种:一对一: @OneToOne一对多: @OneToMany多对一: @ManyToOne多对多: @ManyToMany

 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>

参考地址:http://blog.didispace.com/springbootdata2/

1.大概说一下jpa的好处

3、EntityManager:这个就相当于hibernate的session、mybatis的sqlsessionFactory,定义用于与持久性上下文进行交互的方法。

要访问数据库肯定需要配置数据库的url,账号密码等信息。这些信息可以在application.yml文件中配置

 ===============================================================================================

  前面说过springboot和mybatis的整合,用mybatis的最大优点就是可以看得见sql语句,我们想改就改,想怎么优化就怎么优化。

本案例使用gradle构建,前端使用thymeleaf,数据库用到了H2和mysql,使用jpa完成crud操作。**1、添加依赖:**build.gradle:

spring: datasource: url: jdbc:mysql://127.0.0.1:3306/数据库名 username: 账号 password: 密码

spring boot搭建项目后,想要数据进行持久化操作,更进一步的完善项目的话,就要使用到一个具体的ORM了。而spring boot中完美的支持了spring-data-jpa。

  但是用过hibernate的小伙伴应该知道,hibernate几乎是看不见sql语句的,因为hibernate底层自动生成,但是前提是你要配置好数据库表和一个javabean的映射关系,也比较麻烦,所以就有了jpa,jpa是一个规范,不是框架(这么说很抽象,你可以把jpa当成一个接口,而hibernate是其中的一个实现类),那么我们使用jpa,那么间接的就使用了hibernate。

buildscript { ext { springBootVersion = '1.5.2.RELEASE' } //自定义版本 ext['thymeleaf.version'] = '3.0.3.RELEASE' ext['thymeleaf-layout-dialect.version'] = '2.2.0' ext['hibernate.version'] = '5.2.8.Final' repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") }}apply plugin: 'java'apply plugin: 'eclipse'apply plugin: 'org.springframework.boot'apply plugin: 'io.spring.dependency-management'group = 'com.zhu'version = '0.0.1-SNAPSHOT'sourceCompatibility = 1.8repositories { mavenCentral()}dependencies { //jpa依赖 compile('org.springframework.boot:spring-boot-starter-data-jpa') compile('org.springframework.boot:spring-boot-starter-web') //thymeleaf依赖 compile('org.springframework.boot:spring-boot-starter-thymeleaf') //mysql驱动 compile('mysql:mysql-connector-java:6.0.5') //H2数据库 runtime('com.h2database:h2:1.4.193') testCompile('org.springframework.boot:spring-boot-starter-test')}

这里先打断一下,如果想要修改数据源的实现,可以在java代码的配置类中配置想要的数据源实现的bean。比如我使用alibaba的druid数据源实现,除了在pom.xml中加入依赖之外,需要在配置类中加入对应bean的配置:

这一篇就使用spring-data-jpa进行入门的数据持久化处理

  那为什么这么麻烦呢?直接使用hibernate不就好了吗?

2、配置thymeleaf、H2和jpa:*application.properties:*

 @Autowired Environment environment; @Bean public DataSource dataSource() throws SQLException { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(environment.getProperty("spring.datasource.url")); dataSource.setUsername(environment.getProperty("spring.datasource.username"));//用户名 dataSource.setPassword(environment.getProperty("spring.datasource.password"));//密码 dataSource.setInitialSize; dataSource.setMaxActive; dataSource.setMinIdle; dataSource.setMaxWait; dataSource.setValidationQuery("SELECT 1"); dataSource.setTestOnBorrow; dataSource.setTestOnReturn; dataSource.setTestWhileIdle; dataSource.setPoolPreparedStatements; dataSource.setFilters("mergeStat"); return dataSource; }

===============================================================================================

  举个很简单的例子,接口Animal,两个实现类Dog、Cat;假如有个项目我们要使用Dog里的crud方法,直接Animal animal = new Dog();然后animal.xx();

#thymeleaf相关配置spring.thymeleaf.encoding=UTF-8spring.thymeleaf.cache=falsespring.thymeleaf.mode=HTML5#启用h2控制台spring.h2.console.enabled=true#jpa相关配置spring.jpa.show-sql=truespring.jpa.hibernate.ddl-auto=update

这是spring4推荐的使用java类进行配置的方式。

本篇数据库使用mysql,所以pom加入依赖需要两个

  过了一段时间我们又有一个项目要使用Cat里面的crud方法,还是Animal animal = new Cat();然后animal.xxx();

注意:这里没有配置mysql,先演示H2数据库的用法;spring.jpa.hibernate.ddl-auto的值有以下几个:create ---- 每次运行该程序,没有表格会新建表格,表内有数据会清空;

继续,然后就是spring data jpa的配置了,因为是采用hibernate来实现的,所以配置中与hibernate有一定联系:

澳门新濠3559 1澳门新濠3559 2

  有没有觉得,代码几乎一样,我们只需要搞清楚Animal中的方法,就能使用两个类,学习的成本降低了差不多一半,真正的事半功倍。

create-drop ---- 每次程序结束的时候会清空表;

spring: jpa: hibernate: ddl-auto: update show-sql: true
<!--jpa  hibernate-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--mysql连接架包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

  jpa的实现常见的hibernate,OpenJPA,TopLink,EclipseJPA这几种,虽然我只用过hibernate,但是,你学会了jpa之后,另外几种你也就会了,因为方法和操作hibernate一样。

update ---- 每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新;

其中ddl-auto有4种策略,与hibernate一样。create:每次启动项目,先删除之前创建的表结构,再根据实体类创建表结构。create-drop :每次启动项目,根据实体类创建表结构,每次终止项目,删除所有表结构。update:每次启动项目,验证实体类对应的数据库表结构,如果不一致就更新结构,如创建新表,新增字段等。validate :每次启动项目,验证实体类对应的数据库表结构,如果不一致就抛出异常。

View Code

  还有就是,开发jpa和开发hibernate的居然是同一个作者...emmmm...

validate ---- 运行程序会校验数据与数据库的字段类型是否相同,不同会报错。所以一般情况下用update就行了。

一般使用update。

 

  再说一下hibernate和spring整合的时候,应该发现了Dao层还是要写贼多的东西,各种crud方法要慢慢实现;即使用jpa之后,spring整合jpa(实现产品为hibernate),还是摆脱不了要实现crud方法,虽然代码少写了一点,但是治标不治本;

3、实体层:*User.java:*

2.实体类接下来随便写个实体类:

结构如下:

  但是就当jpa和Spring Data整合之后,你几乎看不到代码了!就一个接口放在那里,即使你有特殊的需求,你只要写个方法,方法名符合一定的规范,就ok了,你都不用实现(当然,实际的项目中不下心可能就碰到了特别复杂的需求,那么还是老老实实的写sql吧!)。

import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;@Entity // 标识这个类是实体public class User { @Id // 标识主键 @GeneratedValue(strategy=GenerationType.IDENTITY) //自增策略 private Long id; private String name; private String email;}
@Entity(name = "sys_student")public class Student { @Id private String code; private String name; private String age; private String banji; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getBanji() { return banji; } public void setBanji(String banji) { this.banji = banji; }}

【entity与domain,dao与repository的区别是什么,看附录2】

  spring data是spring的一个子项目,专门针对持久化层的,我们用过的spring data radis,spring data rabbitmq都是这个项目的模块之一。

注意:这里省略了set、get方法以及构造方法;这样自动建表时表中字段与属性名一致,比如name属性对应数据库表中字段也是name,如果要自定义,可以用在属性上用@Column()注解;表名默认与实体类名一致,可以在类上加@Table()注解来自定义。

@Entity注解表示该类是一个实体类,name属性表示对应的数据库表名。@Id注解顾名思义,就是指该属性作为数据库的主键。jpa规范中还有很多注解,这里只用到了最主要的两个。

 澳门新濠3559 3

2.简单的搭建一下环境 

4、dao层:*UserDao.java:*

有了实体类,需要对这个实体类编写增删改查的代码。此时便到了spring data jpa展现威力的时候了。

配置文件application.properties

  首先,创建springboot项目,要导入的模块web mysql jpa 1.5.18

public interface UserDao extends CrudRepository<User, Long> {}

3.dao层接口新建一个接口,作为student的dao层接口。

【在首次启动之后,将spring.jpa.hibernate.ddl-auto=create 修改为spring.jpa.hibernate.ddl-auto=update,以免下次启动重新创建所有的数据表】

  话说以前我这版本应该是1.5.16啊,怎么偷偷的趁我不注意自动给我升级到1.5.18了......

注意:第一:这个就是简单的实现crud操作,所以继承CrudRepository即可,其它接口如下:Repository:标记型接口,表示任何继承它的类都是仓库接口类。CrudRepository:包含了10种crud方法。PagingAndSortingRepository:除了10中crud方法外,多了分页和排序。JpaRepository:比又多了一些其他的常用方法。所以在项目开发中继承JpaRepository就行了。

/** * Created by liuruijie on 2017/2/18. * student dao */public interface StudentDao extends JpaRepository<Student, String>{ //按照姓名和班级查询 List<Student> findByNameAndBanji(String name, String banji); //如果配置了@Qurey注解,则会按照里面的sql语句进行查询 @Query(value = "select s from #{#entityName} s where age<?1") List<Student> customselect(Integer age);}

【或者 直接将值设置为update,也是可以实现首次创建表,且之后实体字段变化或新增实体,都会自动在数据库中更新且不会删除原来的表和数据,所以建议直接使用update,但是不会打印创建表的sql语句】

澳门新濠3559 4

第二:springData Jpa 还可以自定义方法,只要符合命名规范,就不用我们自己实现。比如要根据用户名和密码查询用户,就可以定义一个findByNameAndPwd()方法,直接调用就行,不需要自己实现。命名规范如下图:

这个接口继承于JpaRepository接口,后者提供了几乎所有常用的crud方法。写完dao层接口后,下一步通常是编写实现类,然而,到这里就行了,根本不用自己实现。

【application.properties字段详解请看:http://www.cnblogs.com/sxdcgaq8080/p/7890218.html】

澳门新濠3559 5

澳门新濠3559 6image.png澳门新濠3559 7image.png

4.使用我们使用一下这个接口,在controller中注入它。

澳门新濠3559 8澳门新濠3559 9

  然后配置文件配置数据源

第三:其实这里取名UserDao不太好,daoData Access Objects的缩写,意思为数据访问对象,这里使用Jpa,根据命名规范应该叫做UserRepository,就像mybatis中应该叫做UserMapper一样。

/** * Created by liuruijie on 2017/2/18. * student controller */@RestController@RequestMapping("student")public class StudentController { //注入自己建的dao接口 @Autowired StudentDao studentDao; //根据主键获取 @GetMapping public Object selectOne(@PathVariable String code){ System.out.println; return studentDao.findOne; } //自定义查询1 @GetMapping("nameAndBanji") public Object findByNameAndBanji(String name, String banji){ return studentDao.findByNameAndBanji(name, banji); } //自定义查询2 @GetMapping("age/{age}") public Object selectByAge(@PathVariable Integer age){ return studentDao.customselect; } //修改 @PutMapping public Object update(@PathVariable String id, Student student) { student.setCode; return studentDao.save; } //新增 @PostMapping public Object insertOne(Student student){ studentDao.save; return "ok"; }}
#view
spring.mvc.view.prefix = /WEB-INF/views/
spring.mvc.view.suffix = .jsp


#datasource
spring.datasource.continue-on-error=false 
spring.datasource.url=jdbc:mysql://localhost:3306/orderdiscount
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

澳门新濠3559 10

第四:jpa没有直接提供分页方法,若是要分页,请看下面的例子:接口中的方法:

测试一下是否真的能用。先在数据库中插入几条记录。

View Code

  配置一个javabean去对应和一张表对应

Page<User> findByAge(int age, Pageable pageable);

澳门新濠3559 11插入记录澳门新濠3559 12根据主键查询澳门新濠3559 13自定义查询1澳门新濠3559 14自定义查询2

日志配置文件 logback-spring.xml

澳门新濠3559 15

调用时:

发现完全没问题,也就是说只要我们继承了spring data jpa提供的接口,我们就可以获得基本的一些crud方法,并且自定义的方法也不用自己写实现就能使用。

【日志文件详解请看:http://www.cnblogs.com/sxdcgaq8080/p/7852858.html】

  来看看现在的dao层是什么鬼。

 Pageable pageable = PageRequest.of(page,size); Page<User> result = UserRepository.findByAge(20,pageable);

spring data jpa自定义查询方法主要有3种方式1.按一定规则命名的方法

澳门新濠3559 16澳门新濠3559 17

  看清楚,这是一个接口,而且不用标示注解!

上述代码表示分页查询age为20的的User。先要构建一个Pageable对象,传入分页信息,再把pageable对象传入查询方法中。

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 findByFirstname,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 findByAgeNotNull … 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<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> 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
<?xml version="1.0" encoding="UTF-8"?>

<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <contextName>logback</contextName>
    <!--定义日志文件的存储地址目录-->
    <property name="LOG_HOME" value="E:/log/"/>


    <!--输出到控制台-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <withJansi>true</withJansi>
        <encoder>
            <!--<pattern>%d %p (%file:%line)- %m%n</pattern>-->
            <!--格式化输出:%d:表示日期    %thread:表示线程名     %-5level:级别从左显示5个字符宽度  %msg:日志消息    %n:是换行符-->
            <pattern>%black(控制台-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger) - %cyan(%msg%n)</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--输出到文件-->
    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}logback.%d{yyyy-MM-dd-HH-mm}[%i].log</fileNamePattern>
            <maxFileSize>10kb</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <!--格式化输出:%d:表示日期    %thread:表示线程名     %-5level:级别从左显示5个字符宽度  %msg:日志消息    %n:是换行符-->
            <pattern>文件记录-%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="console" />
        <appender-ref ref="file" />
    </root>

    <logger name="com.sxd.controller"/>
    <logger name="com.sxd.util.LogTestController" level="WARN" additivity="false">
        <appender-ref ref="console" />
    </logger>



</configuration>

澳门新濠3559 18

5、service层:因为本案例service层并无其他逻辑,所以直接省略。

2.@NamedQurey注解这个注解是实体类上的注解,用于指定一个方法名对应的查询语句。

View Code

  为了方便,就不写service层了,直接controller层

6、controller层:*UserController.java:*

@Entity(name = "sys_student")@NamedQuery(name = "User.namedquery" , query = "select s from sys_student s where s.age<20")public class Student {···

public interface StudentDao extends JpaRepository<Student, String>{··· //namedQuery List<Student> namedquery();···

 

澳门新濠3559 19

@RestController@RequestMappingpublic class UserController { @Autowired private UserDao userDao; /** * 查询所有用户 * * @param model * @return */ @GetMapping public ModelAndView list(Model model) { model.addAttribute("userList", userDao.findAll; model.addAttribute("title", "用户管理"); return new ModelAndView("user/list", "userModel", model); } /** * 根据id查询用户 * * @param id * @param model * @return */ @GetMapping public ModelAndView view(@PathVariable Long id, Model model) { User user = userDao.findOne; model.addAttribute("user", user); model.addAttribute("title", "查看用户"); return new ModelAndView("user/view", "userModel", model); } /** * 获取创建表单页面 * * @param model * @return */ @GetMapping public ModelAndView createForm(Model model) { model.addAttribute("user", new User; model.addAttribute("title", "创建用户"); return new ModelAndView("user/form", "userModel", model); } /** * 保存或更新用户 * * @param user * @return */ @PostMapping public ModelAndView saveOrUpdateUser(User user) { user = userDao.save; return new ModelAndView("redirect:/users"); } /** * 删除用户 * * @param id * @return */ @GetMapping("/delete/{id}") public ModelAndView delete(@PathVariable Long id) { userDao.delete; return new ModelAndView("redirect:/users");// 重定向到list页面 } /** * 获取修改用户的界面 * * @param id * @param model * @return */ @GetMapping("/modify/{id}") public ModelAndView modify(@PathVariable Long id, Model model) { User user = userDao.findOne; model.addAttribute("user", user); model.addAttribute("title", "修改用户"); return new ModelAndView("user/form", "userModel", model); }}

这个方式就是将某个名称和查询语句绑定在一起,此时调用namedquery()方法就相当于执行@NamedQurey中配置的查询语句。

要想和数据库打交道,这里还是关系型数据库,那就来个实体和数据库的表对应起来

  然后运行springboot项目,就会在数据库创建user表

从上面的代码可以看到,虽然dao层只是简单的继承了CrudRepository,没有做任何实现,但是我们在controller层调用时却可以使用findOne、findAll、delete、save方法,底层已经帮我们实现这些方法了,我们只需调用就行了。

3.@Qurey注解这个注解是方法上的注解,作用于dao层接口的方法上,顾名思义,加上这个注解,就可以将一个查询语句与一个方法绑定起来。

实体User.java

澳门新濠3559 20

7、前端:*页头:header.html*

public interface StudentDao extends JpaRepository<Student, String>{··· //如果配置了@Qurey注解,则会按照里面的sql语句进行查询 @Query(value = "select s from #{#entityName} s where age<?1") List<Student> customselect(Integer age);···

澳门新濠3559 21澳门新濠3559 22

  

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"><head><meta charset="UTF-8"><title>thymeleaf in action</title></head><body><div th:fragment="header"> <h1>Thymeleaf in action</h1> <a href="/users" >首页</a></div></body></html>

?是占位符,1是参数序号,从1开始。#{#entityName}是SpEl表达式,这里的值就是Student的实体名,即@Entity注解中设置的name。

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;
    }
}

  我手动往表里添加几条数据

页脚:footer.html

View Code

澳门新濠3559 23

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"><head><meta charset="UTF-8"><title>thymeleaf in action</title></head><body><div th:fragment="footer"> <a href="#" >邮箱</a></div></body></html>

spring-data-jpa的优势体现就是下面这个接口啦!!

  打开浏览器,输入url:

form.html:

【spring-data-jpa的详细介绍和复杂使用http://www.cnblogs.com/sxdcgaq8080/p/7894828.html澳门新濠3559,】

澳门新濠3559 24

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"><head><meta charset="UTF-8"><title>thymeleaf in action</title></head><body><div th:replace="~{fragments/header :: header}"></div><h3 th:text="${userModel.title}">test</h3><form action="/users" th:action="@{/users}" method="POST" th:object="${userModel.user}"> <input type="hidden" name="id" th:value="*{id}"> 名称:<br> <input type="text" name="name" th:value="*{name}"><br> 邮箱:<br> <input type="text" name="email"th:value="*{email}"> <input type="submit" value="提交"></form><div th:replace="~{fragments/footer :: footer}"></div></body></html>

Dao层放在repository目录下  接口UserRepository.java

澳门新濠3559 25

list.html:

澳门新濠3559 26澳门新濠3559 27

  这是最简单的使用了,其实这里关键是userDao到底可以用哪些方法,截了一下图,大概可以看到基本的crud方法应该是都实现了,你只需要传入相关的参数即可。

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"><head><meta charset="UTF-8"><title>thymeleaf in action</title></head><body><!-- 引用头部信息 --><!-- 在fragments下的header文件下有名为header的片段 --><div th:replace="~{fragments/header :: header}"></div><h3 th:text="${userModel.title}"></h3><div> <a href="/users/form.html" th:href="@{/users/form}">创建用户</a></div><table border="1"> <thead> <tr> <td>ID</td> <td>Email</td> <td>Name</td> </tr> </thead> <tbody> <tr th:if="${userModel.userList.size()} eq 0"> <td colspan="3">没有用户信息</td> </tr> <tr th:each="user : ${userModel.userList}"> <td th:text="${user.id}"></td> <td th:text="${user.email}"></td> <td ><a th:href="@{'/users/' ${user.id}}" th:text="${user.name}"></a></td> </tr> </tbody></table><div th:replace="~{fragments/footer :: footer}"></div></body></html>
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,String>{

    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);
}

  话说每次都说crud,但是具体是哪几个单词知道吗?C,R,U,D,看到名字应该知道意思吧!

view.html:

View Code

  在springdata jpa中,增加和修改方法都是save()

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"><head><meta charset="UTF-8"><title>thymeleaf in action</title></head><body><div th:replace="~{fragments/header :: header}"></div><h3 th:text="${userModel.title}">test</h3><div> <p><strong>ID:</strong></p> <p><strong>Name:</strong></p> <p><strong>Email:</strong></p></div><div> <a th:href="@{'/users/delete/' ${userModel.user.id}}">删除</a> <a th:href="@{'/users/modify/' ${userModel.user.id}}">修改</a></div><div th:replace="~{fragments/footer :: footer}"></div></body></html>

 

澳门新濠3559 28

8、测试:创建用户:

就这么几步,就能进行数据的持久化操作了。

  删除,delete()

澳门新濠3559 29image.png

启动创建数据表如下,执行的sql语句如下:

澳门新濠3559 30

用户列表:

【如果spring.jpa.hibernate.ddl-auto=update,也会创建数据表,但是不会有SQL语句打印出来】

  查询,方法就多了,但都是类似findxxx(),具体的自己去尝试

澳门新濠3559 31image.png

澳门新濠3559 32

澳门新濠3559 33

点击用户名字还可以进行删除和修改操作,这里不再截图。接下来说说H2数据库。

 

  

9、H2数据库:H2数据库是一个内存数据库,数据保存在内存中,项目一重启数据就没了。且其无需安装任何服务或者客户端,要在项目中使用也不用怎么配置,直接添加其依赖即可。那么如何查看数据是否保存到了H2数据库中呢?它提供了一个网页版控制台,网址为http://localhost:8080/h2-console,这个控制台默认是不启用的,所以刚才在application.properties中加上了spring.h2.console.enabled=true配置。开启后,访问该网址就会出现如下界面:

 

3.貌似比较高级的操作

澳门新濠3559 34image.png点击connect就可以查看到数据:澳门新濠3559 35image.png注意,如果你首次登录http://localhost:8080/h2-console,JDBC URL显示的不是jdbc:h2:mem:testdb,就要改成这个,否则进去看不到数据。

好了建立一个单元测试类,使用一下自己写的Repository层的方法和已经封装好的一些方法:

 所谓高级的操作,无外乎就是自定义嘛!

如果使用了H2数据库后还想使用MySQL,只需要在appication.properties中加上其配置即可,如下:

澳门新濠3559 36

  因为有的高手就觉得我为什么用你这个方法啊,我能不能自定义啊?比如我要..emmm...按照名字来查找记录,ok,jpa也提供给你,但是你要想好一个很特别很特殊的方法名,这个方法名不单单你认识,而且还要程序认识。(玛德,想个方法名都这么多要求,日了狗哦!)

#配置MySQL数据源spring.datasource.url=jdbc:mysql:///blog?useSSL=false&serverTimezone=GMTspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.username=#spring.datasource.password=#

JunitTest.java是放在test目录下的

  那么我们在dao层自定义一个方法试试 澳门新濠3559 37

H2数据库会自动检测你有没有配置其他数据库,如果配置了,H2就会退出江湖,如果把mysql的配置注释掉了,H2就会重出江湖。值得注意的是:如果你的MySQL驱动用的是6.0以上的版本,要像上面一样在jdbc的url中添加serverTimezone=GMT,否则会报错。

澳门新濠3559 38澳门新濠3559 39

  

springData Jpa十分强大,有了它,dao层几乎不需要自己写了。上面的案例只是演示了简单的crud,其他方法以及自定义方法老铁们也可以试一试。还有这个项目是基于gradle的,基于maven的也是一样的开发方法,只是添加依赖的方式不同而已。

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);

        //查询所有
//        List<User> list = userRepository.findAll();
//        if(Objects.nonNull(list)){
//            list.forEach(i->{
//                System.out.println(i);
//            });
//        }

        //删除所有
        userRepository.deleteAll();

    }
}

  controller层我试试这个方法

以上内容属于个人笔记整理,如有错误,欢迎批评指正!

View Code

澳门新濠3559 40

 

  看看浏览器能不能访问,能访问,ok

 然后右键在单元测试方法上 运行起来即可。【单元测试,具体看:http://www.cnblogs.com/sxdcgaq8080/p/7894444.html】

澳门新濠3559 41

澳门新濠3559 42

  所以现在我们要知道的就是自定义的方法名,要符合什么规范?弄清楚这个了,那自定义方法也就ok了。

 

  其实规则就跟原生的sql语句差不多,就是提取了关键字而已,比如我要根据name模糊查找,sql语句就是xxx where name like ‘王%’,关键字就是like;于是我们方法名就是findByNameLike(String name),括号里就是我们要传进去的条件,相当于‘王%’。

执行完sava方法之后,就会执行插入,sql语句如下:

  我猜底层应该会解析方法名,拼接成sql语句,向数据库发送sql语句进行操作,本质上,一个方法就是一条sql语句。

 澳门新濠3559 43

  还有一些关键词,And,Or,Between,OrderBy等等,都可以用于方法名。

数据库中也插入成功:

  我随便列举一下几个方法名参考一下:

澳门新濠3559 44

findByUserName(String userName);

 

findByUserNameOrEmail(String username, String email);

 下面的方法  自己一个一个测试即可。

countByUserName(String userName);

==========================================结束语====================================================

``findByEmailLike(String email);

这章就是简单的使用spring-data-jpa进行和数据库交互的操作。数据持久化得以实现,那就解决了项目一个很重大的问题了。但这里只是最最开始的一些,后面会把spring-data-jpa的复杂使用解开面纱。

``List<User> findByUserNameOrderByEmailDesc(String email);

===========================================附录1:===================================================

  看名字应该知道是干什么的了,好好体会一下!sql语句用的熟练了,这个应该不难。

如果有人对spring-data-jpa和hibernate是什么关系存在疑问,可以看看这部分:

4.一点小操作

  ①JPA首先得介绍一下,他只是一套规范和标准,也就是一堆堆的接口,并未实现;

  有的时候理想很丰满,现实却很骨感!你一不小心碰到了一个非常复杂的需求,然而用上面这些规则却总是一副日了狗的表情,你就很怀念用sql语句了!玛德,要是我能用sql语句的话,我不要一分钟就能做好了,现在让我编这个方法名就是特么编不出来啊!

  ②hibernate是对JPA的一种实现,就是你具体执行持久化操作调用的方法内具体干了什么,都是Hibernate实现的;

  ok,springboot data jpa也考虑到了你这种需求,于是我们便能像用mybatis的注解版一样使用jpa了。

  ③spring-data-jpa则是对hibernate实行了再封装,大大的简化了原本DAO层的实现,也就是现在的repository层。因为本章就是用的spring-data-jpa,如果你之前使用的是三大框架还是什么巴拉巴拉之类的,肯定是上去先把项目的目录框架,entity,dao,daoimpl,service,serviceimpl,controller层搭建好,才开发的。

  请看下面dao层的方法,是不是和mybatis注解版十分相似啊?不过要注意,这里注解里面的语句没记错的话应该是hql语句吧,操作的是实体类!

  ④spring  spring-boot官方对hibernate是一直都有支持的,而对mybatis则没有,但并不代表它不能与mybatis集成。【这点有点废话,但是却是想表达】

  当然如果你要写原生sql语句,在@Query里面就要加个属性:nativeQuery=true,就可以写原生sql语句了,很简单,这里不多说。

 

  可以取别名,可以有占位符,占位符可以直接是?;不过别人都是?1:代表第一个占位符;如果还有?2:第二个占位符; 还有?3:第三个占位符。。。占位符和参数一一对应,当然还可以用@Param(“xxx”)和形参进行参数绑定,这时hql语句占位符也会发生变化。

===========================================附录2:===================================================

  我们就不搞这些花里胡哨的了,怎么简单怎么来:

参考自:

澳门新濠3559 45

entity:和数据库数据表绝对对应的实体,放在entity下

  查询只要@Query一个注解就可以了,但是增加,修改,删除还需要另外一个注解@Modifying,再看一个方法。

model:前台需要是什么,model就被处理成什么

澳门新濠3559 46

domain:代表一个对象模块。

  要加那个事务的注解,假如不加,会报错,下图所示,emmm....建议增上改方法除了@Query之外,都加上那这两个注解

 

澳门新濠3559 47

分开来说:

  然后我运行应用,测试了,成功,你们可以自己试试!

①entity【实体】习惯性使用这个,作为实体的包名。entity中有几个属性,对应的数据表中就有几个字段。并且字段类型都保持绝对一致。

  其实后面还有分页,多表查询,有点小麻烦所以我就很不要脸的跳过了,嘿嘿嘿!不过还是大概说一下:

②model【模型】的使用,例如User对象实体中有十个字段,但是前台仅需要username和age的话,那把整个实体传给前台无疑多传输了好些无用的数据。又比如User的sex字段,数据库中存储为男的1,女的2。如果把User对象传给前台,前台js还需要判断一下,而如果sex存储改变了,2为男,1为女,这样js还需要进行改动。所以可以将前台需要的数据封装为model传给前台。而model对象都放在model包下。

  分页就是自己定义一下规则,一页多少数据,多少页,包装成一个对象,放到findAll方法里就可以了;而多表查询,前提是两个类建立好关系(就是一对多,多对一什么的),然后重点就是编写@Query里面的hql语句了;

③domain【域】是一个订单,一个用户信息等概念的划分。比如一个招聘网站的项目,最重要的对象就是简历了,那么简历是怎么存到数据库的呢,不可能用一张表就能存的,因为简历包含基本信息和工作经验,项目经验,学习经验等。基本信息可以存在简历表,但是涉及到多条的就不行,因为没人知道有多少条工作经验,项目经验,所以必须要单独建工作经验表和项目经验表关联到简历基本信息表。但是前台页面是不关心这些的,前台需要的数据就是一个简历所有信息,这时就可以用到domain来处理,domain里面的类就是一个简历对象,包含了简历基本信息以及list的工作经验,项目经验等。这样前端只需要获取一个对象就行了,不需要同时即要获取基本信息,还要从基本信息里面获取工作经验关联的简历编号,然后再去获取对应的工作经验了。

  这里我就是给新手小哥们看一看基本操作,想要深入了解的小伙伴可以自己查查资料看看分页和多表级联操作。

 

  其实本来是不想写这个springboot data jpa的,因为用的比较少,还不如springboot mybatis好玩,不过啊,因为我后面我要说springboot和一个东西的整合,太像springboot jpa了,于是我也顺便说说jpa得了。

===================================================================================================

 

编辑:编程 本文来源:data jpa用起来就很简单,每个实体实例对应该表中

关键词: 澳门新濠3559