目录

8.1 集成JdbcTemplate

8.2 集成Spring Data JPA

8.4 小结


前面讲了这么多,都没有涉及到数据的存储。现在的软件系统多多少少都会涉及到数据库的存储。不管做什么,App、web、C/S客户端软件,都需要将涉及到的数据存储起来,一般来说,目前最常用的数据存储方式还是关系型数据库。

本章我们就一起来看下在以Spring Boot为基础的项目中,如何方便地操作数据库。

Spring Boot应用中访问数据库的方式有多种。常用的有下面几种:

  • JdbcTemplate
  • Spring Data JPA
  • Mybatis集成(本文不涉及,后续再写)

8.1 集成JdbcTemplate

JdbcTemplate是Spring Boot提供的一个数据操作组件,封装了基本的数据库操作,本节主要针对常用数据库mysql来展示如何使用JdbcTemplate进行数据操作。

首先,在pom文件中添加JdbcTemplate和mysql的支持。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>

接下来,在application.properties中添加数据源配置项。

spring.datasource.url=jdbc:mysql://localhost:3306/m_customer
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.main.allow-bean-definition-overriding=true

新增类UserService,在其中直接注入JdbcTemplate使用。

package cn.com.hanbinit.customer.service;import cn.com.hanbinit.customer.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;@Service
public class UserService {@Autowired
private JdbcTemplate jdbcTemplate;/**
* 创建用户
* @param nickname
* @param age
*/
public Boolean create(String nickname, Integer age){int number = jdbcTemplate.update("insert into tb_user(nickname, age) values(?,?)", nickname, age);if(number == 1){return true;}return false;
}/**
* 根据用户Id删除单个用户
* @param userId
* @return
*/
public Boolean deleteById(Integer userId){int number = jdbcTemplate.update("delete from tb_user where id = ?", userId);if(number == 1){return true;}return false;
}/**
* 根据Id获取单个用户信息
* @param userId
* @return
*/
public User getUserById(Integer userId){return jdbcTemplate.queryForObject("select id, nickname, age from tb_user whereid = ?", (resultSet, i) -> {User user = new User();user.setId(resultSet.getInt("id"));user.setNickname(resultSet.getString("nickname"));user.setAge(resultSet.getInt("age"));return user;}, userId);
}/**
* 获取所有用户列表
* @return
*/
public List<User> getAllUsers(){List<User> userList = jdbcTemplate.query("select *from tb_user", (resultSet,i) -> {User user = new User();user.setId(resultSet.getInt("id"));user.setNickname(resultSet.getString("nickname"));user.setAge(resultSet.getInt("age"));return user;});return userList;}
}

其中使用到的User类,代码如下:

package cn.com.hanbinit.customer.model;/*** 用户基本信息*/public class User {private Integer id;private String nickname;private Integer age;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}}

最后,将UserService注入到UserController中,就可以直接使用了。

@Autowired
private UserService userService;……@GetMapping("/users/{userId}")
public User getUserInfoByUserId(@PathVariable Integer userId){return userService.getUserById(userId);
}@PostMapping("/users")
public Boolean saveUser(@RequestBody User user){return userService.create(user.getNickname(), user.getAge());
}@GetMapping("/users")
public List<User> getAllUsers(){return userService.getAllUsers();
}@DeleteMapping("/users/{userId}")
public Boolean deleteUserById(@PathVariable Integer userId){return userService.deleteById(userId);
}

UserController省略了部分之前已经存在的代码。

以上的代码操作了数据库中的tb_user表,表结构如下:

CREATE TABLE `tb_user` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`nickname` varchar(50) DEFAULT NULL,`age` int(3) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

通过图8.1-8.3可以看出来,我们通过POST来向数据库中添加数据。

图8.1 调用接口,向数据库中谈添加数据

图8.2 查询单个用户信息

图8.3 删除Id=2的用户

在查询所有的用户列表,可以看到,id=2的数据已经被删除掉,如图8.4所示。

图8.4 用户列表查询

8.2 集成Spring Data JPA

JPA相传是为了整合第三方ORM框架,建立统一持久化标准而来的。在大名鼎鼎的Hibernate中,JPA的使用整合地就相当完美。JPA本身是一系列的接口,Hibernate实现了JPA的接口后,今天我们要介绍的Spring Data JPA,其实也可以简单理解为Spring实现了JPA的接口。

实际项目开发中,大部分的数据库操作都是相对简单的单表“增删改差”。正常情况下,开发人员需要写许多额外的代码来实现很多的基本数据操作。Spring Data JPA提供了最基本的JpaRepository接口,继承这个接口就可以实现绝大多数的数据库操作。

下面我们改造一下order微服务,添加基本订单表,使用Spring Data JPA实现数据表的简单操作。

首先在pom.xml中添加Spring Data JPA的引用。

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

在application.properties中添加如下配置项。

spring.datasource.url=jdbc:mysql://localhost:3306/m_order
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.main.allow-bean-definition-overriding=true
spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop

其中,spring.jpa.properties.hibernate.hbm2ddl.auto是hibernate的配置属性,其主要作用是:自动创建、更新、验证数据库表结构。该参数的几种配置如下:

  • create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
  • create-drop:每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。
  • update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
  • validate:每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。

添加model包,新建类Order,如下代码,指定了接下来需要操作的实体对象。

package cn.com.hanbinit.order.model;import javax.persistence.*;
import java.util.Date;// @Entity 指明这个类是一个可以持久化的对象
@Entity
// @Table 指明了本类对应的数据库中表的信息
@Table(name = "tb_order")
public class Order {// @Id修饰的变量是主键@Id// @GeneratedValue 是一个简单的主键生成策略,在Mysql中指的是Auto-Increment@GeneratedValueprivate Long id;private String title;// 指明成员变量createDate对应的表字段为create_date且不能为空@Column(name="create_date", nullable = false)private Date createDate;// 指明成员变量createBy对应的表字段为create_by@Column(name="create_by", nullable = false)private String createBy;public Long getId() {return id;}public void setId(Long id) {this.id = id;    }public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public Date getCreateDate() {return createDate;}public void setCreateDate(Date createDate) {this.createDate = new Date();}public String getCreateBy() {return createBy;}public void setCreateBy(String createBy) {this.createBy = createBy;}
}

接下来,创建repository包,并新建接口OrderRepository继承JpaRepository。代码如下:

package cn.com.hanbinit.order.repository;import cn.com.hanbinit.order.model.Order;
import org.springframework.data.jpa.repository.JpaRepository;public interface OrderRepository extends JpaRepository<Order, Long> {}

上面代码中的JpaRepository接口是Jpa中简单的一个接口类,通过下面的代码可方便看到其中定义了很多的相对口语化的方法。

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T,
ID>, QueryByExampleExecutor<T> {/** (non-Javadoc)* @see org.springframework.data.repository.CrudRepository#findAll()*/List<T> findAll();/** (non-Javadoc)* @seeorg.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)*/List<T> findAll(Sort sort);/** (non-Javadoc)* @seeorg.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)*/List<T> findAllById(Iterable<ID> ids);/** (non-Javadoc)* @seeorg.springframework.data.repository.CrudRepository#save(java.lang.Iterable)*/<S extends T> List<S> saveAll(Iterable<S> entities);/*** Flushes all pending changes to the database.*/void flush();/*** Saves an entity and flushes changes instantly.** @param entity* @return the saved entity*/<S extends T> S saveAndFlush(S entity);/*** Deletes the given entities in a batch which means it will create a single{@link Query}. Assume that we will clear* the {@link javax.persistence.EntityManager} after the call.** @param entities*/void deleteInBatch(Iterable<T> entities);/*** Deletes all entities in a batch call.*/void deleteAllInBatch();/*** Returns a reference to the entity with the given identifier.** @param id must not be {@literal null}.* @return a reference to the entity with the given identifier.* @see EntityManager#getReference(Class, Object)* @throws javax.persistence.EntityNotFoundException if no entity exists forgiven {@code id}.*/T getOne(ID id);/** (non-Javadoc)* @seeorg.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)*/@Override<S extends T> List<S> findAll(Example<S> example);/** (non-Javadoc)*@seeorg.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example,org.springframework.data.domain.Sort)*/@Override<S extends T> List<S> findAll(Example<S> example, Sort sort);}

接口中定义的这些方法都是可以在继承了这个类的接口中直接使用的。使用代码:

@Autowired
private OrderRepository orderRepository;

将OrderRepository注入到OrderController中,并在OrderController中添加接口。

/**
* 获取所有的用户
* @return*/@GetMapping("/orders")public List<Order> queryAllOrders(){return orderRepository.findAll();}/**
* 新增用户
* @param order
* @return*/@PostMapping("/orders")public Order createOrder(@RequestBody Order order){order.setCreateDate(new Date());return orderRepository.save(order);}

启动order微服务,在数据库中可以看到已经自动创建表tb_order,使用desc
tb_order;查看表结构,可以看到如图8.5所示结果。

图8.5 自动创建表tb_order的结构

在postman中模拟调用上面新增的保存order信息接口,可以看到图8.6所示的结果。

图8.6 模拟调用使用Spring Data JPA实现的order保存功能

使用图8.6中的方式一次向数据库中插入多条数据,然后将请求的Method改为GET重新调用。可以看到图8.7中的结果。

图8.7 模拟调用使用Spring Data JPA实现的order列表查询功能

Spring Data JPA的上手难度比较低,对单表的操作也很方便,但是对于多表关联操作来说略显麻烦,接下来笔者会带大家一起了解下Spring Data JPA是如何处理多表关联操作情况的。

8.4 小结

本章通过为之前创建的微服务项目添加JdbcTemplate,Spring Data JPA支持,大家可以掌握到如何为Spring Boot项目添加关系型数据库的操作支持。

第8章 离不开的数据库相关推荐

  1. 国开mysql答案_国开MySQL数据库应用形考任务.doc

    <国开MySQL数据库应用形考任务.doc>由会员分享,可在线阅读,更多相关<国开MySQL数据库应用形考任务.doc(13页珍藏版)>请在装配图网上搜索. 1.国开MySQL ...

  2. 随便聊聊浪潮开务数据库

    今天这个话题挺随意,我们来聊聊浪潮开务数据库,原因主要是我的微信朋友圈被这个数据库刷屏了.当然我对这款号称多模数据库的非开源数据库也很感兴趣,也有很多疑问,希望各位专家能帮忙答疑解惑,揭开这款即将发布 ...

  3. 计算机检索技术与技巧的检索式为,第四章计算机检索技术和数据库检索方式.ppt...

    第四章计算机检索技术和数据库检索方式 第四章 计算机信息检索的基本技术与方法 一.计算机信息检索的基本技术: 布尔逻辑.截词检索.加权检索,位置算符等. 在进行计算机检索时,有时有一些比较复杂的课题, ...

  4. 源来是你-Vol.38 | 浪潮开务数据库招人辣!准备好加入幸福感爆棚的KW家族了么?...

    KW 家族又双叒叕诚挚邀请大家入伙啦!在这里,你可以坐拥舒适优雅的工作环境,携手和蔼可亲的同袍战友,共创数据库美好未来! 01 数据库存储内核研发工程师 工作职责: 负责存储子系统的研发路线规划.架构 ...

  5. 针对第2章习题6的SPJ数据库,为项目名称为“一汽”的工程项目建立一个供应情况的视图V_SPJ,视图中应包括供应商代码SNO,零件代码PNO,供应数量QTY,并针对该视图完成下列查询 (1)找出一汽

    针对第2章习题6的SPJ数据库,为项目名称为"一汽"的工程项目建立一个供应情况的视图V_SPJ,视图中应包括供应商代码SNO,零件代码PNO,供应数量QTY,并针对该视图完成下列查 ...

  6. 第一章——程序数据集散地:数据库

    第一章--程序数据集散地:数据库 数据库的必要性 数据库可以高效的且条理分明的存储数据,更加迅速和方便的处理数据. 数据库的基本概念 1.SQLServer 由microsoft微软推出,多用于C#语 ...

  7. Kubernetes使用开务数据库简介

    为什么选择 Kubernetes 容器是打包和运行应用程序的好方式.在生产环境中,我们需要管理运行应用程序的容器,并确保不会停机.如果一个容器发生故障,则需要启动另一个容器.如果系统处理此行为,会不会 ...

  8. 第五十一章 管理镜像 - 镜像的数据库注意事项

    文章目录 第五十一章 管理镜像 - 镜像的数据库注意事项 镜像的数据库注意事项 `IRIS` 实例兼容性 成员字节顺序注意事项 使用 `^DATABASE` 例程创建镜像数据库 第五十一章 管理镜像 ...

  9. 《精通自动化测试框架设计》—第2章 2.6节使用数据库

    本节书摘来自异步社区<精通自动化测试框架设计>一书中的第2章,第2.6节使用数据库,作者陈冬严 , 邵杰明 , 王东刚 , 蒋涛,更多章节内容可以访问云栖社区"异步社区" ...

  10. mysql 拷贝数据库 表存在却打不开_mysql数据库文件复制后表打不开

    mysql数据库文件复制后表打不开找了很多方法最终解决了.InnoDB只有frm表结构,拷贝过去mysql后说表不存在网上说还要拷贝ibdata1文件,但这样的话会覆盖掉mysql本来有的ibdata ...

最新文章

  1. 活见鬼,明明删除了数据,空间却没减少!
  2. day1 作业二:多级菜单操作
  3. linux用户管理最常用的三个文件说明(不完整版)
  4. 老鼠怕猫是鼻子决定的?!
  5. 云服务器系统重装为windows,并进行文件传输
  6. 动态修改dom node的两种方法性能比较
  7. oracle进程结构中完成更新,Oracle 进程结构
  8. 云计算之路-阿里云上:拔云见日的那一刻,热泪盈眶
  9. OpenGL入门程序一:绘制简单的矩形
  10. 林期苏曼属性标签编辑_CAD技巧之增强属性编辑器 属性文字
  11. 最新圣思园经典Java培训教学全套
  12. 2019 第十届蓝桥杯Java省赛B组个人题解
  13. 走出校门,工作4个月的工作感想
  14. android p蓝色壁纸,iPhone和Android的最佳蓝色系壁纸分享
  15. HTML中head与body标签
  16. weui.js中的picker自定义实现移动端联动
  17. 虚幻引擎图文笔记:用Two Bone IK实现手扶墙
  18. I2C 子系统(三):I2C Driver
  19. couldn‘t upgrade db schema: insert into ACT_GE_PROPERTY values (‘common.sche[已解决]
  20. 隧道工具proxytunnle

热门文章

  1. HEVC帧内预测学习(一)CTU、CU、PU、TU单元划分的理解
  2. 快恢复二极管工作原理、反向恢复时间详解
  3. IEEE爬取摘要并翻译成中文
  4. 计算机二级 java编程题_计算机等级二级考试辅导:Java IO单元机试题及解答(第2部分)...
  5. 修改ubuntu键盘布局
  6. 共议新时代的文化自信与守正创新,第十四届文化中国讲坛举办
  7. ts类中的private和protected
  8. 三种LCA算法(一):Doubly算法(倍增算法)
  9. 5号字对应的数字字号_5号字体是多少pt-字号,尺寸
  10. 防盗系统Java_java小区防盗报警系统