Spring JPA CURD

1 概述
Spring Data JPA是一个框架,对 Java Persistence API 进行再次封装。 Java Persistence API 是Java EE中的规范,它的实现产品有最有名的如Hibernate、Eclipse Link等,都是ORM框架。而ORM的本质是对JDBC进行了封装。ORM可以让程序员以OO的思维来操作关系数据库。

使用Spring Data JPA有以下优点:

不再需要手动建表
不再需要 写插入SQL
不再需要 写修改SQL
不再需要 写删除SQL
简单的 查询SQL, 不要写(查找一条和查找所有记录),复杂的需要写
2 关键技术
如何使用Spring Data JPA呢?

第一步,在Spring boot工程中引入依赖。

org.springframework.boot spring-boot-starter-data-jpa 第二步,建立一个数据库,并建立数据库访问的用户名和密码,并设置数据库访问权限。过程略。

第三步,设置数据库连接属性。在application.properties配置文件中添加以下配置:

#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/liyongzhendb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=liyongzhendb
spring.datasource.password=liyongzhendb

#Spring Boot 2.0 includes HikariDataSource by default
spring.datasource.type = com.zaxxer.hikari.HikariDataSource

spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=12
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.max-lifetime=1200000
spring.datasource.hikari.auto-commit=true

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect
spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=false
spring.jpa.show-sql=true
配置很通俗易懂。仅介绍下spring.jpa.hibernate.ddl-auto,它的值是update,意思是实体有变动,会相应的修改表,如实体添加属性,表会相应添加字段。

更多application.properties配置见官方文档 https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

第五步,创建实体。实体即是轻量级持久对象域。通常,实体表示关系数据库中的表,并且每个实体实例对应于该表中的一行。更多理论参数Java EE官方文档 https://docs.oracle.com/javaee/6/tutorial/doc/bnbqa.html

创建的实体如下:

package com.wangshenghua.model;

import java.time.LocalDate;
import java.util.Arrays;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Email;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.springframework.format.annotation.DateTimeFormat;

@Entity
@Table(name = “user”)
public class User {

@NotNull
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

@NotNull(message = "请输入姓名")
@Size(min = 2, max = 30, message = "姓名在2~30个字符之间")
private String name;

@NotNull(message = "请输入年龄")
@Min(message = "年龄至少15岁", value = 15)
private Integer age;

@NotNull(message = "请选择性别")
private String gender;

@NotNull
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate dateOfBirth;

@NotEmpty(message = "请输入邮箱")
@Email(message = "邮箱格式不对")
private String email;

@NotNull
@Size(min = 1, max = 5, message = "选择课程")
private String[] course;

@NotEmpty(message = "请选择故乡")
private String hometown;

@NotEmpty(message = "请选择兴趣爱好")
private String[] hobbies;

private String memo;

public User() {
}

public User(@NotNull long id,
        @NotNull(message = "请输入姓名") @Size(min = 2, max = 30, message = "姓名在2~30个字符之间") String name,
        @NotNull(message = "请输入年龄") @Min(message = "年龄至少15岁", value = 15) Integer age,
        @NotNull(message = "请选择性别") String gender,
        @NotEmpty(message = "请输入邮箱") @Email(message = "邮箱格式不对") String email) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.email = email;
}

public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Integer getAge() {
    return age;
}

public void setAge(Integer age) {
    this.age = age;
}

public String getGender() {
    return gender;
}

public void setGender(String gender) {
    this.gender = gender;
}

public LocalDate getDateOfBirth() {
    return dateOfBirth;
}

public void setDateOfBirth(LocalDate dateOfBirth) {
    this.dateOfBirth = dateOfBirth;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public String[] getCourse() {
    return course;
}

public void setCourse(String[] course) {
    this.course = course;
}

public String getHometown() {
    return hometown;
}

public void setHometown(String hometown) {
    this.hometown = hometown;
}

public String[] getHobbies() {
    return hobbies;
}

public void setHobbies(String[] hobbies) {
    this.hobbies = hobbies;
}

public String getMemo() {
    return memo;
}

public void setMemo(String memo) {
    this.memo = memo;
}

@Override
public String toString() {
    return "User [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + ", dateOfBirth="
            + dateOfBirth + ", email=" + email + ", course=" + Arrays.toString(course) + ", hometown=" + hometown
            + ", hobbies=" + Arrays.toString(hobbies) + ", memo=" + memo + "]";
}

}
实体有3个关键点:其一注释@Entity指定此类是一个实体。其二注释@Table指定此实体在关系数据库中映射的表。其三注释@Id和@GeneratedValue用于指定主键和主键生成策略。

第六步,创建实现CrudRepository接口的接口。实现CrudRepository接口就具备了CURD的能力。

package com.wangshenghua.dao;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.wangshenghua.model.User;

@Repository
public interface UserRepository extends CrudRepository {

}
Spring框架在分层上规划特别好。数据库访问层,使用注释@Repository。别使用@Controller或@Service哦。

CrudRepository接口是泛型,这里需要代入具体的实体名User,及实体的主键类型Long。

第七步,控制器层如何调用UserRepository?

package com.wangshenghua.controller;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import com.wangshenghua.dao.UserRepository;
import com.wangshenghua.model.User;

@Controller
public class UserController {

private static final Logger log = LoggerFactory.getLogger(UserController.class);

final static Map RADIO_GENDER = Collections.unmodifiableMap(new LinkedHashMap() {
    private static final long serialVersionUID = 1L;
    {
        put("男", "男");
        put("女", "女");
    }
});

final static Map CHECK_COURSE = Collections.unmodifiableMap(new LinkedHashMap() {
    private static final long serialVersionUID = 1L;

    {
        put("Java程序设计", "java");
        put("Spring", "spring");
        put("MySQL", "mysql");
        put("HTML", "html");
    }
});

final static Map SELECT_HOMETOWN = Collections.unmodifiableMap(new LinkedHashMap() {
    private static final long serialVersionUID = 1L;
    {
        put("郴州", "郴州");
        put("耒阳", "耒阳");
        put("广州", "广州");
    }
});

final static Map SELECT_HOBBIES = Collections.unmodifiableMap(new LinkedHashMap() {
    private static final long serialVersionUID = 1L;
    {
        put("打球", "打球");
        put("听歌", "听歌");
        put("玩游戏", "玩游戏");
        put("写代码", "写代码");
        put("吃烧烤", "吃烧烤");
    }
});

@Autowired
private UserRepository userDao;

/** 控制器的方法 **/

@GetMapping("/")
public String index() {
    return "redirect:/allUser";
}

@GetMapping("/allUser")
public String allUser(Model model) {
    model.addAttribute("users", userDao.findAll());
    return "list-user";
}

@GetMapping("/adduser")
public String showAddUserForm(Model model) {
    User user = new User();
    model.addAttribute("user", user);
    model.addAttribute("radioItems", RADIO_GENDER);
    model.addAttribute("checkItems", CHECK_COURSE);
    model.addAttribute("selectItems", SELECT_HOMETOWN);
    model.addAttribute("multipleItems", SELECT_HOBBIES);
    return "add-user";
}

@PostMapping("/adduser")
public String addUser(@Valid User user, BindingResult bindingResult, Model model) {

    if (bindingResult.hasErrors()) {
        model.addAttribute("user", user);
        model.addAttribute("radioItems", RADIO_GENDER);
        model.addAttribute("checkItems", CHECK_COURSE);
        model.addAttribute("selectItems", SELECT_HOMETOWN);
        model.addAttribute("multipleItems", SELECT_HOBBIES);
        return "add-user";
    }

    userDao.save(user);
    return "redirect:/allUser";
}

@GetMapping("/edit/{id}") // {id}是占位符
public String showUpdateForm(@PathVariable("id") long id, Model model) { // @PathVariable 路径变量
    Optional user = userDao.findById(id);
    model.addAttribute("user", user);
    return "update-user";
}

@PostMapping("/update/{id}")
public String updateUser(@PathVariable("id") long id, @Valid User user, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "update-user";
    }
    userDao.save(user);
    return "redirect:/allUser";
}

@GetMapping("/delete/{id}")
public String deleteUser(@PathVariable("id") long id, Model model) {
    userDao.deleteById(id);
    return "redirect:/allUser";
}

}
别看代码多,关键代码仅几行:

@Autowired private UserRepository userDao;采用自动注入的方式注入 UserRepository 实例。

userDao.findAll()查找所有,实则调用CrudRepository接口的方法Iterable findAll();

userDao.findById(id)根据主键查找实体, 实则调用CrudRepository接口的方法Optional findById(ID id)

userDao.deleteById(id)根据主键删除实体, 实则调用CrudRepository接口的方法void deleteById(ID id);

第八步,在Spring boot工程的主程序@SpringBootApplication添加扫描实体所在包和Repository所在包的配置。如下:

@EnableTransactionManagement
@EnableJpaRepositories(basePackages = “com.wangshenghua.dao”)
@EntityScan(basePackages = “com.wangshenghua.model”, basePackageClasses = { Application.class, Jsr310JpaConverters.class })
@EnableTransactionManagement表示启用事务管理

@EnableJpaRepositories表示启用 Repository 操作数据库

@EntityScan表示扫描实体

3 总结
本节课程我们学习Spring Data JPA操作关系数据库,来实现增删改查功能。使用 Spring Data JPA操作关系数据库非常简单(相对JDBC而言)。关键步骤仅8步。

越是使用简单的东东,底层代码越是复杂。不仅是Spring对底层进行抽象封装,Java EE组织对JDBC的抽象和封装从未止步。正是有这此组织和个人的除出,才有Java今天的地位。

本节课程源码已经上传到github,可以前往下载。

你可能感兴趣的:(Spring,JPA,CURD,Spring,JPA,CURD)