SpringData JPA学习之CRUD

一、环境准备

springboot 1.5.4环境

数据库:spring的h2内存数据库

application.properties配置

server.port=8080
# 数据源配置
# 表明使用的数据库平台是h2
spring.datasource.platform=h2
spring.datasource.url=jdbc:h2:mem:ssb_test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=root
spring.datasource.password=123456

h2数据库说明

h2数据库是一个基于内存的数据库,十分的轻量级,它提供了一个web控制界面。

具体的配置暂不做介绍,他的可视化界面如下:

操作很简单:

服务启动之后访问地址http://localhost:8080/h2/login.jsp

选择汉语,配置,密码什么的都照着配置文件抄就好了。

1选择数据库(点击左侧的Customer)

2.点击Run

这样就可以看出来他里面的数据

需要注意的,这个数据库声明周期和spring一样,容器关闭了他也关闭了,可以利用spring的声明周期,让测试数据在启动的时候就已经提供好。

pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-accessing-data-jpa</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

二、代码实现

建立一个实体pojo

package com.gysoft.springdatajpa.forall.pojo;

import javax.persistence.*;

@Entity
@Table(name = "Customer")
public class Customer {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;
    protected Customer() {}
    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    @Override
    public String toString() {
        return String.format(
                "Customer[id=%d, firstName='%s', lastName='%s']",
                id, firstName, lastName);
    }
}

这个pojo和数据库的字段一一对应,但是数据库默认的会生成大写加下划线命名的方式,为了使其和pojo里面的字段保持一致,可以在application.properties配置文件里面加入如下的配置进行声明

#解决数据库字段变成驼峰命名的问题,这样的话数据库字段和pojo字段就一样了
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

dao层接口的实现

package com.gysoft.springdatajpa.forall.dao;

/**
 * @Description
 * @Author DJZ-WWS
 * @Date 2019/6/13 9:24
 */

import com.gysoft.springdatajpa.forall.pojo.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface CustomerRepository extends JpaRepository<Customer, Long> {

    /**
     * 根据lastname查找
     * @param lastName
     * @return
     */
    List<Customer> findByLastName(String lastName);

   /**
    * 多条件  根据lastName和firstname
    * @author   weiwensi
    * @date 14:05 2019/6/13
    *@param  firstName
    *@param  lastName
    * @return
    * @throws Exception
    * @version 2.1
    **/


    List<Customer>  findCustomerByFirstNameAndAndLastName(String firstName,String lastName);
    
    
    /**
     * 根据id查询
     * @author   weiwensi
     * @date 14:14 2019/6/13
     *@param
     * @return
     * @throws Exception
     * @version 2.1
     **/

     Customer   findById(Long  id);
    /**
     * 根据firstName查询
     *
     */

    Customer  findByFirstName(String  firstName);


    /**
     * 模糊匹配
     * @param bauer
     * @return
     */
    @Query("select c from Customer c where c.firstName=?1")
    List<Customer> findByFirstName2(String bauer);

 /**
  * 测试实体sql的查询
  * @param lastName
  * @return
  */
 @Query(value = "select * from customer  where lastName=? order by id desc",nativeQuery = true)
   // @Query("select c from Customer c where c.lastName=?1 order by c.id desc")
 List<Customer> findByLastName2(String lastName);

    /**
     * 一个参数,匹配两个字段
     * @param name2
     * @return
     * 这里Param的值和=:后面的参数匹配,但不需要和方法名对应的参数值对应
     */
    @Query("select c from Customer c where c.firstName=:name or c.lastName=:name  order by c.id desc")
    List<Customer> findByName(@Param("name") String name2);

    /**
     * 一个参数,匹配两个字段
     * @param name
     * @return
     * 这里的%只能放在占位的前面,后面不行
     */
    @Query("select c from Customer c where c.firstName like %?1")
    List<Customer> findByName2(@Param("name") String name);

    /**
     * 一个参数,匹配两个字段
     * @param name
     * @return
     * 开启nativeQuery=true,在value里可以用原生SQL语句完成查询
     */
    @Query(nativeQuery = true,value = "select * from Customer c where c.first_name like concat('%' ,?1,'%') ")
    List<Customer> findByName3(@Param("name") String name);
}

这个接口继承了JpaRepository,他的接口方法定义如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.data.jpa.repository;

import java.io.Serializable;
import java.util.List;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;

@NoRepositoryBean
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    List<T> findAll();

    List<T> findAll(Sort var1);

    List<T> findAll(Iterable<ID> var1);

    <S extends T> List<S> save(Iterable<S> var1);

    void flush();

    <S extends T> S saveAndFlush(S var1);

    void deleteInBatch(Iterable<T> var1);

    void deleteAllInBatch();

    T getOne(ID var1);

    <S extends T> List<S> findAll(Example<S> var1);

    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

从这个接口里面可以看出来这个接口里面定义一些基本的增删改查,springjpa我个人认为采用了约束大于配置的思想,基本的增删改查不用写sql很简单就可以实现

他提供了自己的语法配置,具体的配置如下:

 

再次拼接and条件

就是类似这样一步步拼接,实现起来很简单,简单的增删改查基本都满足了。

一些基本的测试如下:(注意每次启动项目都需要重新访问index对应得接口,这里没有整合spring进行优化,后面会进行优化,不必要每次都重新创建测试数据)

 /**
     * 初始化数据
     */
    @RequestMapping("/index")
    public void index() {
        // save a couple of customers
        //这里使用了代理的方式实现了数据的存储


        repository.save(new Customer("Jack", "Bauer"));
        repository.save(new Customer("Chloe", "O'Brian"));
        repository.save(new Customer("Kim", "Bauer"));
        repository.save(new Customer("David", "Palmer"));
        repository.save(new Customer("Michelle", "Dessler"));
        repository.save(new Customer("Bauer", "Dessler"));

    }

    /**
     * 查询所有
     */
    @RequestMapping("/findAll")
    @ResponseBody
    public void findAll(){
        Iterable<Customer> result = repository.findAll();
        for (Customer customer:result){
            System.out.println(customer.toString());
        }
        System.out.println("-------------------------------------------");
    }
    /**
     * 查询ID为1的数据
     */
    @RequestMapping("/findOne")
    @ResponseBody
    public Customer findOne(){
        Customer result = repository.findOne(1L);
        if(result!=null){
            System.out.println(result.toString());
        }
        System.out.println("-------------------------------------------");
        return result;
    }
    /**
     * 查询ID为1的数据
     */
    @RequestMapping("/delete")
    public void delete(){

        System.out.println("删除前数据:");
        Iterable<Customer> customers = repository.findAll();
        for (Customer customer:customers){
            System.out.println(customer.toString());
        }

        System.out.println("删除ID=3数据:");
        Customer cu = repository.findById(3L);
        if(null==cu){
            throw new  IllegalArgumentException("您要删除的数据已经不存在");
        }
        repository.delete(3L);

        System.out.println("删除后数据:");
        customers = repository.findAll();
        for (Customer customer:customers){
            System.out.println(customer.toString());
        }
        System.out.println("-------------------------------------------");
    }

    /**
     * 根据lastName查询
     */
    @RequestMapping("/findByLastName")
    @ResponseBody
    public  List<Customer>  findByLastName(){
        List<Customer> result = repository.findByLastName("Bauer");
        for (Customer customer:result){
            System.out.println(customer.toString());
        }
        System.out.println("-------------------------------------------");

        List<Customer> customerByFirstNameAndAndLastName = repository.findCustomerByFirstNameAndAndLastName("Jack", "Bauer");

        customerByFirstNameAndAndLastName.forEach(e->{
            System.out.println("根据firstname和lastName查询的结果"+e);

        });

      return customerByFirstNameAndAndLastName;
    }

springdatajpa 除了这些简单的增删改查,还可以通过注解进行一个sql的指定,如果你想写sql那就这么干吧

 /**
     * 模糊匹配
     * @param bauer
     * @return
     */
    @Query("select c from Customer c where c.firstName=?1")
    List<Customer> findByFirstName2(String bauer);

 /**
  * 测试实体sql的查询
  * @param lastName
  * @return
  */
 @Query(value = "select * from customer  where lastName=? order by id desc",nativeQuery = true)
   // @Query("select c from Customer c where c.lastName=?1 order by c.id desc")
 List<Customer> findByLastName2(String lastName);

    /**
     * 一个参数,匹配两个字段
     * @param name2
     * @return
     * 这里Param的值和=:后面的参数匹配,但不需要和方法名对应的参数值对应
     */
    @Query("select c from Customer c where c.firstName=:name or c.lastName=:name  order by c.id desc")
    List<Customer> findByName(@Param("name") String name2);

    /**
     * 一个参数,匹配两个字段
     * @param name
     * @return
     * 这里的%只能放在占位的前面,后面不行
     */
    @Query("select c from Customer c where c.firstName like %?1")
    List<Customer> findByName2(@Param("name") String name);

    /**
     * 一个参数,匹配两个字段
     * @param name
     * @return
     * 开启nativeQuery=true,在value里可以用原生SQL语句完成查询
     */
    @Query(nativeQuery = true,value = "select * from Customer c where c.first_name like concat('%' ,?1,'%') ")
    List<Customer> findByName3(@Param("name") String name);

这里的sql大部分都是使用了JPQL的语言方式,如果你需要使用原生的sql,你可以通过注解的参数nativeQuery=true 进行。

切换譬如上面的

@Query(value = "select * from customer  where lastName=? order by id desc",nativeQuery = true)
  // @Query("select c from Customer c where c.lastName=?1 order by c.id desc")
List<Customer> findByLastName2(String lastName);

对于里面的一些问题稍微解释一下:

?加数字表示占位符,?1代表在方法参数里的第一个参数,区别于其他的index,这里从1开始

=:加上变量名,这里是与方法参数中有@Param的值匹配的,而不是与实际参数匹配的

JPQL的语法中,表名的位置对应Entity的名称,字段对应Entity的属性,详细语法见相关文档

官方文档地址:

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

这样基本实现了大部分的简单增删改查。附一个我的application。properties的完整配置

server.port=8080
# 数据源配置
# 表明使用的数据库平台是h2
spring.datasource.platform=h2
spring.datasource.url=jdbc:h2:mem:ssb_test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=root
spring.datasource.password=123456
#spring.datasource.schema=classpath:db/schema.sql
#spring.datasource.data=classpath:db/data.sql
# 进行该配置后,h2 web consloe就可以在远程访问了。否则只能在本机访问。
spring.h2.console.settings.web-allow-others=true
# 进行该配置,你就可以通过YOUR_URL/h2-console访问h2 web consloe。YOUR_URL是你程序的访问URl。
spring.h2.console.path=/h2
# 进行该配置,程序开启时就会启动h2 web consloe。当然这是默认的
spring.h2.console.enabled=true

#连接池配置
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
#初始化连接:连接池启动时创建的初始化连接数量
spring.datasource.dbcp2.initial-size=50
#最大活动连接:连接池在同一时间能够分配的最大活动连接的数量, 如果设置为非正数则表示不限制
spring.datasource.dbcp2.max-active=250
#最大空闲连接:连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放,如果设置为负数表示不限制
spring.datasource.dbcp2.max-idle=50
#最小空闲连接:连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接,如果设置为0则不创建
spring.datasource.dbcp2.min-idle=5
#最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间(以毫秒计数),超过时间则抛出异常,如果设置为-1表示无限等待
spring.datasource.dbcp2.max-wait-millis=10000
#SQL查询,用来验证从连接池取出的连接,在将连接返回给调用者之前.如果指定,则查询必须是一个SQL SELECT并且必须返回至少一行记录
spring.datasource.dbcp2.validation-query=SELECT 1
#当建立新连接时被发送给JDBC驱动的连接参数,格式必须是 [propertyName=property;]。注意:参数user/password将被明确传递,所以不需要包括在这里。
spring.datasource.dbcp2.connection-properties=characterEncoding=utf8

# JPA配置
#hibernate提供了根据实体类自动维护数据库表结构的功能,可通过spring.jpa.hibernate.ddl-auto来配置,有下列可选项:
#1、create:启动时删除上一次生成的表,并根据实体类生成表,表中数据会被清空。
#2、create-drop:启动时根据实体类生成表,sessionFactory关闭时表会被删除。
#3、update:启动时会根据实体类生成表,当实体类属性变动的时候,表结构也会更新,在初期开发阶段使用此选项。
#4、validate:启动时验证实体类和数据表是否一致,在我们数据结构稳定时采用此选项。
#5、none:不采取任何措施。
spring.jpa.hibernate.ddl-auto=update
#spring.jpa.show-sql用来设置hibernate操作的时候在控制台显示其真实的sql语句。
spring.jpa.show-sql=true
#让控制器输出的json字符串格式更美观。
spring.jackson.serialization.indent-output=true
#解决数据库字段变成驼峰命名的问题,这样的话数据库字段和pojo字段就一样了
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
#日志配置
logging.level.com.xiaolyuh=debug
logging.level.org.springframework.web=debug
logging.level.org.springframework.transaction=debug
logging.level.org.apache.commons.dbcp2=debug

#开启对AOP的支持
spring.aop.auto=true
#设置代理模式 true(cglib) false(java JDK代理)
spring.aop.proxy-target-class=true

debug=false

后面继续学习SpringDataJPA的其他东西。

参考:http://www.spring4all.com/article/500

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

在此感谢我的同事万强的悉心指教。

个人代码github地址

https://github.com/wws11/SpingDataJpa

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值