Spring boot 数据访问
1.spring boot 数据访问概述
spring boot 默认采用Spring Data 的方式统一处理数据访问层。
常见数据库依赖启动器
名称 | 对应数据库 |
---|---|
spring-boot-start-data-jpa | Spring Data JPA Hibernate |
spring-boot-start-data-mongodb | MongoDB , Spring Data MongoDB |
spring-boot-start-data-neo4j | Neo4j数据库, Spring Data Neo4j |
spring-boot-start-data-redis | Redis |
2.Spring boot 整合Mybatis
-
准备工作
- 创建数据库
create database springbootdata; CREATE TABLE `t_article` ( `id` int(20) NOT NULL AUTO_INCREMENT COMMENT '文章id', `title` varchar(200) DEFAULT NULL COMMENT '文章标题', `content` longtext COMMENT '文章内容', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; INSERT INTO `t_article` VALUES ('1', 'Spring Boot基础入门', '从入门到精通讲解...'); INSERT INTO `t_article` VALUES ('2', 'Spring Cloud基础入门', '从入门到精通讲解...'); CREATE TABLE `t_comment` ( `id` int(20) NOT NULL AUTO_INCREMENT COMMENT '评论id', `content` longtext COMMENT '评论内容', `author` varchar(200) DEFAULT NULL COMMENT '评论作者', `a_id` int(20) DEFAULT NULL COMMENT '关联的文章id', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; INSERT INTO `t_comment` VALUES ('1', '很全、很详细', '狂奔的蜗牛', '1'); INSERT INTO `t_comment` VALUES ('2', '赞一个', 'tom', '1'); INSERT INTO `t_comment` VALUES ('3', '很详细', 'kitty', '1'); INSERT INTO `t_comment` VALUES ('4', '很好,非常详细', '张三', '1'); INSERT INTO `t_comment` VALUES ('5', '很不错', '张杨', '2');
- 创建项目
使用Spring Initializr 方式创建项目,并勾选SQL 中的 Mybatis Framework 和 MySQL Driver
这样pom.xml 文件中就会自动添加了mybatis 的依赖 和mysql 的依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- 创建实体类
package cn.edu.sjzc.chapter03.domain;
import java.util.List;
public class Article {
private Integer id;
private String title;
private String content;
private List<Comment> commentList;
}
package cn.edu.sjzc.chapter03.domain;
public class Comment {
private Integer id;
private String content;
private String author;
private Integer aId;
}
-
添加alibaba 的druid 数据源依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency>
-
编写application.properties 配置文件
# 数据库驱动类
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 数据库地址
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC
# 数据库用户名和密码
spring.datasource.username=root
spring.datasource.password=123456
# 数据源的自定义配置,配置后将覆盖原有的默认配置
# 数据库类型
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
# 初始化连接数
spring.datasource.initialSize=20
# 最小空闲连接数
spring.datasource.minIdle=10
# 最大连接数
spring.datasource.maxActive=100
-
整合
-
Mapper 接口方式整合(适用于简单的SQL 语句)
-
编写Mapper 接口
package cn.edu.sjzc.chapter03.mapper; import cn.edu.sjzc.chapter03.domain.Comment; import org.apache.ibatis.annotations.*; @Mapper public interface CommentMapper { @Select("select * from t_comment where id = #{id}") public Comment findComment(Integer id); @Insert("insert into t_comment values (#{id},#{content},#{author},#{aId})") public void insertComment(Comment comment); @Update("update t_comment set comment=#{comment}") public void updateComment(Comment comment); @Delete("delete from t_comment where id=#{id}") public void deleteComment(Integer id); }
-
测试
package cn.edu.sjzc.chapter03; @SpringBootTest class Chapter03ApplicationTests { @Autowired private CommentMapper commentMapper; @Test public void dbTest(){ Comment comment = commentMapper.findComment(1); System.out.println(comment); } }
输出结果:Comment{id=1, content=‘很全、很详细’, author=‘狂奔的蜗牛’, aId=null}
注意 Comment类 的aId 属性为驼峰命名,数据库中t_comment 表对应的字段为a_id,类属性和字段没有对应上,所以打印出的aId 为null
在application.properties 配置文件中加入以下配置,表示mybatis 开启驼峰命名
-
开启驼峰命名规则
mybatis.configuration.map-underscore-to-camel-case=true ``` 重新测试结果:Comment{id=1, content='很全、很详细', author='狂奔的蜗牛', aId=1}
-
-
配置文件方式整合Mybatis(适用于复杂的SQL 语句)
-
创建Mapper 接口
package cn.edu.sjzc.chapter03.mapper; import cn.edu.sjzc.chapter03.domain.Article; import org.apache.ibatis.annotations.Mapper; @Mapper public interface ArticleMapper { public Article selectArticle(Integer id); }
2. 创建xxMapper.xml 映射配置文件 ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.edu.sjzc.chapter03.mapper.ArticleMapper"> <resultMap id="articleMap" type="cn.edu.sjzc.chapter03.domain.Article"> <id property="id" column="id"></id> <result property="title" column="title"></result> <result property="content" column="content"></result> <collection property="commentList" ofType="Comment"> <id property="id" column="cid"></id> <result property="content" column="content"></result> <result property="author" column="author"></result> <result property="aId" column="aId"></result> </collection> </resultMap> <select id="selectArticle" resultMap="articleMap" parameterType="Integer"> select a.*,c.id cid,c.content,c.author,c.a_id from t_article a,t_comment c where a.id = c.a_id and a.id=#{id} </select> </mapper>
-
在全局配置文件(application.properties)中配置 xxMapper.xml 的路径 和 配置实体类别名
配置Mybatis 的xxMapper.xml文件路径
mybatis.mapper-locations=classpath:mapper/ArticleMapper.xml
配置xxMapper.xml 文件中实体类别名
mybatis.type-aliases-package=cn.edu.sjzc.chapter03.domain
4. 测试 ```java package cn.edu.sjzc.chapter03; @SpringBootTest class Chapter03ApplicationTests { @Autowired private ArticleMapper articleMapper; @Test public void dbTest2(){ Article article = articleMapper.selectArticle(1); System.out.println(article); } }
输出结果:
Article{id=1, title=‘Spring Boot基础入门’, content=‘从入门到精通讲解…’, commentList=[Comment{id=1, content=‘从入门到精通讲解…’, author=‘狂奔的蜗牛’, aId=null}, Comment{id=2, content=‘从入门到精通讲解…’, author=‘tom’, aId=null}, Comment{id=3, content=‘从入门到精通讲解…’, author=‘kitty’, aId=null}, Comment{id=4, content=‘从入门到精通讲解…’, author=‘张三’, aId=null}]}
-
3.spring boot 整合JPA
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
2. 创建ORM 实体类
实体类的成员变量与表属性相对应
@Entity(name="**xxx**") 注解加在类上,表示该**实体类**与**xxx表**对应,@Id 注解加在**主键**对应的**成员变量**上,@GeneratedValue (**strategy** = GenerationType.IDENTITY) 和@Id 注解一起使用,表示主键自增,@Column(name="**xxx**") 注解加在成员变量上,表示该**成员变量**与表中的**xxx**属性相对应。
```java
package cn.edu.sjzc.chapter03.domain;
import javax.persistence.*;
@Entity(name="t_comment") // 表示实体类对应的表
public class Discuss {
@Id // 加载主键上
@GeneratedValue(strategy = GenerationType.IDENTITY) // 表示主键自增
private Integer id;
@Column(name = "content")
private String content;
@Column(name = "author")
private String author;
@Column(name = "aId")
private Integer aId;
// 省略set 方法
@Override
public String toString() {
return "Discuss{" +
"id=" + id +
", content='" + content + '\'' +
", author='" + author + '\'' +
", aId=" + aId +
'}';
}
}
-
创建JpaRepository 接口的子接口
自定义DiscussRepository 接口继承JpaRepository 接口,JpaRepository 接口包含了常用的CRUD(增删改查)方法,如果常用CRUD方法无法满足需要,可以在自定义接口中自定义方法,如下。
@Query(value=“sql”) 注解加在自定义方法上,sql表示调用该方法所执行的sql语句,该sql语句中**?1**,表示该方法的第一个参数。@Transaction 注解加在有数据库变更的方法上,如果调用该方法的service 层已经添加了@Transaction 注解,则自定义接口中可以省略该注解,否则不能省略。@Modifying 注解加在有@Query 注解且有数据库变更的方法上。
package cn.edu.sjzc.chapter03.repository; import cn.edu.sjzc.chapter03.domain.Discuss; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.transaction.annotation.Transactional; import java.awt.print.Pageable; import java.util.List; public interface DiscussRepository extends JpaRepository<Discuss,Integer> { // 查询author 非空的Discuss 集合 public List<Discuss> findByAuthorNotNull(); // 根据文章id 查询Discuss 集合 @Query("select c from t_comment c where c.aId=?1") public List<Discuss> getDiscussPaged(Integer aid, Pageable pageable); @Query(value = "select c from t_comment c where c.aId=?1",nativeQuery = true) public List<Discuss> getDiscussPaged2(Integer aid, Pageable pageable); // 根据评论id 修改评论作者 @Transactional @Modifying @Query("update t_comment c set author=?1 where id=?2") public int updateDiscuss(String author,Integer id); //根据评论id 删除评论 @Transactional @Modifying @Query("delete from t_comment c where c.id=?1") public int deleteDiscussById (Integer id); }
-
测试
@Autowired private DiscussRepository discussRepository; @Test public void jpaTest(){ // 自定义方法 List<Discuss> byAuthorNotNull = discussRepository.findByAuthorNotNull(); for (Discuss discuss : byAuthorNotNull) { System.out.println(discuss); } } @Test public void jpaTest2(){ // 父接口定义的方法 List<Discuss> discusses = discussRepository.findAll(); for (Discuss discuss : discusses) { System.out.println(discuss); } } @Test public void jpaTest3(){ // 父接口中定义的方法 Optional<Discuss> byId = discussRepository.findById(1); System.out.println(byId); } @Test public void jpaTest4(){ // 自定义方法 discussRepository.deleteDiscussById(4); }
4.spring boot 整合 redis
-
准备工作
-
安装redis
下载地址: https://github.com/MicrosoftArchive/redis/releases
-
启动redis
-
安装图形界面: https://www.jianshu.com/p/6895384d2b9e
-
-
整合
-
添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
创建实体类
-
Person 类
package cn.edu.sjzc.chapter03.domain; import org.springframework.data.annotation.Id; import org.springframework.data.redis.core.RedisHash; import org.springframework.data.redis.core.index.Indexed; import java.util.List; @RedisHash("persons") public class Person { @Id private String id; @Indexed private String firstName; @Indexed private String lastName; private Address address; private List<Family> familyList; }
-
Address 类
package cn.edu.sjzc.chapter03.domain; import org.springframework.data.redis.core.index.Indexed; public class Address { @Indexed private String city; @Indexed private String country; }
-
Family 类
package cn.edu.sjzc.chapter03.domain; import org.springframework.data.redis.core.index.Indexed; public class Family { @Indexed private String type; @Indexed private String username; }
-
-
创建自定义接口
package cn.edu.sjzc.chapter03.repository; import cn.edu.sjzc.chapter03.domain.Person; import org.springframework.data.repository.CrudRepository; import java.awt.print.Pageable; import java.util.List; public interface PersonRepository extends CrudRepository<Person,String> { List<Person> findByLastName(String lastname); List<Person> findPersonByLastName(String lastname, Pageable pageable); List<Person> findByFirstNameAndLastName(String firstname,String lastname); List<Person> findByAddress_City(String city); List<Person> findByFamilyList_Username(String username); }
-
测试
package cn.edu.sjzc.chapter03; import ... @SpringBootTest class Chapter03ApplicationTests { // redis 测试 @Autowired private PersonRepository personRepository; @Test void testRedis(){ Person person = new Person(); person.setFirstName("li"); person.setLastName("ze"); Address address = new Address(); address.setCity("石家庄"); address.setCountry("中国"); person.setAddress(address); Family family = new Family(); family.setType("爸爸"); family.setUsername("li"); Family family1 = new Family(); family1.setType("妈妈"); family1.setUsername("wang"); List<Family> familyList = new ArrayList<>(); familyList.add(family); familyList.add(family1); person.setFamilyList(familyList); personRepository.save(person); } @Test void testRedis2(){ List<Person> personList = personRepository.findByLastName("ze"); for (Person person : personList) { System.out.println(person); } } }
运行test1,打开redis 图形界面,发现已将person 对象存储到redis 数据库中
运行test2,将redis 中的数据存储到java 对象中
-