专栏首页品茗ITSpringBoot入门建站全系列(五)使用Spring-data-jpa操作数据库
原创

SpringBoot入门建站全系列(五)使用Spring-data-jpa操作数据库

SpringBoot入门建站全系列(五)使用Spring-data-jpa操作数据库

SpringBoot操作数据库有多种方式,如

JDBC直接操作:太古老了,没人愿意这样玩

Mybatis插件:比较时髦,比较适合sql复杂,或者对性能要求高的应用,因为sql都是自己写的。

Spring-data-jpa: 使用hibernate作为实现,基本上不需要写sql,因为sql都是统计的,总是会产生多余的查询,性能上相对而言会低,但不绝对,影响性能的因素是多种的,这里说的性能是 从最终的查询的sql来对比的,毕竟生成的sql没有经过深思熟虑写出来的性能好。

JdbcTemplate:spring在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。Spring-data-jpa引入的时候,JdbcTemplate必然会被引入的。

当然还有其他中间件,主流使用的就是Mybatis和Spring-data-jpa。

一、引入依赖

需要同时引入数据库的connector和数据源datasource。和使用mybatis一样,只需要替换Mybatis引入的jar依赖即可。

依赖如下:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
</dependency>

完整的依赖如下所示:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>cn.pomit</groupId>
	<artifactId>testjpa</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
	</parent>
	<name>testjpa</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </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>

二、配置数据库连接信息

server.port=8080

spring.application.name=pomit

spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=cff
spring.datasource.password=123456

spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
spring.datasource.dbcp2.max-wait-millis=60000
spring.datasource.dbcp2.min-idle=20
spring.datasource.dbcp2.initial-size=2
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.connection-properties=characterEncoding=utf8
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.test-while-idle=true
spring.datasource.dbcp2.test-on-borrow=true
spring.datasource.dbcp2.test-on-return=false

#JPA Configuration:  
spring.jpa.database=MySQL
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy

这里面,包含了数据库连接信息、数据源的连接池配置信息、jpa配置信息。

spring.jpa.hibernate.ddl-auto属性,是对表的操作:

  • create 启动时删数据库中的表,然后创建,退出时不删除数据表
  • create-drop 启动时删数据库中的表,然后创建,退出时删除数据表 如果表不存在报错
  • update 如果启动时表格式不一致则更新表,原有数据保留
  • validate 项目启动表结构进行校验 如果不一致则报错
  • none 啥都不做

spring.jpa.hibernate.naming.implicit-strategy和spring.jpa.hibernate.naming.physical-strategy是对表和实体字段映射的默认处理方式。

实体名称映射到数据库中时,分成两个步骤:

  • 第一个阶段是从对象模型中提取一个合适的逻辑名称,这个逻辑名称可以由用户指定,通过@Column和@Table等注解完成,也可以通过被Hibernate的ImplicitNamingStrategy指定;
  • 第二个阶段是将上述的逻辑名称解析成物理名称,物理名称是由Hibernate中的PhysicalNamingStrategy决定;

PhysicalNamingStrategy和ImplicitNamingStrategy的区别:

  • 从处理的效果上来看,其实没有什么区别,但是从程序设计分层的角度来看,类似于MVC的分层,ImplicitNamingStrategy只管模型对象层次的处理,PhysicalNamingStrategy只管映射成真实的数据名称的处理,但是为了达到相同的效果,比如将userName映射城数据列时,在PhysicalNamingStrategy决定映射成user_name,但是在ImplicitNamingStrategy也可以做到;
  • 从处理的场景来看, 无论对象模型中是否显式地指定列名或者已经被隐式决定,PhysicalNamingStrategy都会应用; 但是对于ImplicitNamingStrategy,仅仅只有当没有显式地提供名称时才会使用,也就是说当对象模型中已经指定了@Table或者@Entity等name时,设置的ImplicitNamingStrategy并不会起作用。

所以,这里的配置,映射到表字段时,所有点都被下划线替换,骆驼情况也被下划线替换。默认情况下,所有表名都以小写生成

三、使用Spring-data-Jpa

3.1 表与Java实体

假设我们有一张这个表user_role :

在这里插入图片描述

实体:

package cn.pomit.testboot.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "user_role")
public class UserRole {
	@Id
	private int id;
	@Column(name = "user_name")
	private String userName;
	private String role;
	private String phone;

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

	public int getId() {
		return id;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getUserName() {
		return userName;
	}

	public void setRole(String role) {
		this.role = role;
	}

	public String getRole() {
		return role;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getPhone() {
		return phone;
	}

}

3.2 建立Dao层进行数据库访问

UserRoleDao:

import java.util.List;

import org.springframework.data.repository.CrudRepository;

import cn.pomit.testboot.domain.UserRole;

public interface UserRoleDao extends CrudRepository<UserRole, Integer> {
	List<UserRole> findByRole(String role);
}

可以看到,使用Spring-data-jpa就是就这么简单,只需要继承CrudRepository即可。

同时,Spring-data-jpa还支持findBy + 字段(And 字段)进行查询。deleteBy + 字段(And 字段)进行删除。

分页等其他操作后续再讲。

四、service逻辑调用Dao。

UserRoleService:

import java.util.List;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.pomit.testboot.domain.UserRole;
import cn.pomit.testboot.mapper.UserRoleDao;

@Service
public class UserRoleService {
	@Autowired
	UserRoleDao userRoleDao;

	public List<UserRole> selectAll() {
		return (List<UserRole>) userRoleDao.findAll();
	}

	public void saveTest(UserRole userRole) {
		userRoleDao.save(userRole);
	}

	@Transactional
	public void update(Integer id, String phone) {
		UserRole userRole = userRoleDao.findById(id).orElse(null);
		if (userRole != null) {
			userRole.setPhone(phone);
			userRoleDao.save(userRole);
		}

	}

	@Transactional
	public void delete(Integer id) {
		userRoleDao.deleteById(id);
	}

	public List<UserRole> findByRole(String role) {
		return userRoleDao.findByRole(role);
	}
}

五、开放接口调用service

MybatisRest:

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.pomit.testboot.domain.UserRole;
import cn.pomit.testboot.service.UserRoleService;

@RestController
@RequestMapping("/db")
public class TestJpaRest {
	@Autowired
	UserRoleService userRoleService;

	@RequestMapping(value = "/query")
	public List<UserRole> query() {
		return userRoleService.selectAll();
	}

	@RequestMapping(value = "/testFind")
	public List<UserRole> testFind() {
		return userRoleService.findByRole("ADMIN");
	}

	@RequestMapping(value = "/save")
	public String save() {
		UserRole userRole = new UserRole();
		userRole.setRole("TEST");
		userRole.setUserName("TEST");
		userRole.setPhone("3424234");
		userRoleService.saveTest(userRole);
		return "0000";
	}

	@RequestMapping(value = "/update")
	public String update() {
		userRoleService.update(4, "454");
		return "0000";
	}

	@RequestMapping(value = "/delete")
	public String delete() {
		userRoleService.delete(4);
		return "0000";
	}

}

六、启动

package cn.pomit.testboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JpaApplication {
	public static void main(String[] args) {
		SpringApplication.run(JpaApplication.class, args);
	}
}

喜欢这篇文章么,喜欢就加入我们一起讨论SpringBoot技术吧!

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android NDK编程(六)--- JNI中类参数的传递与返回

    代码往往在不断写的情况下学习到新的东西,本以为NDK程序这块出完番外篇后应该就不用再出了,结果在使用过程中还是会有新的东西加入,所以又有了今天这一篇。

    Vaccae
  • Java中的静态绑定与动态绑定

    由上面我们可以得出结论,如果一个方法不可被继承或者继承后不可被覆盖,那么这个方法就采用的静态绑定。

    俺也想起舞
  • Android NDK编程(七)--- JNI中List结构的类数据返回

    上一篇文章我们介绍了《Android NDK编程(六)--- JNI中类参数的传递与返回》学会了使用类的返回,在做开发中,往往我们返回的参数带有List<类>的...

    Vaccae
  • Java中的按值传递

    这个时候可能会有疑问了,为什么add方法可以修改List数组,但是append和addNum却没有修改传进来的值

    俺也想起舞
  • RestAssured接口系列|环境搭建

    http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.h...

    测试邦
  • Scala使用

    Scala是一门主要以Java虚拟机(JVM)为目标运行环境并将面向对象和函数式编程语言的最佳特性综合在一起的编程语言。你可以使用Scala编写出更加精简的程序...

    俺也想起舞
  • Gradle 笔记

    Task 是 Gradle 构建的最小执行单元。 clean 就是一种最常见的 Task。

    tonglei0429
  • Dubbo注册中心

    关于源码和原理的分析,我们都需要找寻一个切入点,找到切入点的前提是你要知道注册中心的功能是什么,注册中心相信大家都不陌生,每一个通用的注册中心都需要提供两个基本...

    shysh95
  • spark RPC原理

    Spark-1.6以后RPC默认使用Netty替代Akka,在Netty上加了一层封装,为实现对Spark的定制开发,所以了解Spark中RPC的原理还是有必要...

    俺也想起舞
  • Android NDK编程(八)--- JNI中List结构的类数据做为参数

    上一篇文章我们介绍了《Android NDK编程(七)--- JNI中List结构的类数据返回》,这章主要介绍把List结构的类做为参数在方法中进行实现。

    Vaccae

扫码关注云+社区

领取腾讯云代金券