Spring Data JPA
JPA: Java Persistence API,提供 POJO 物件持久化的標準規格,可把 Java 物件直接映射到資料庫中
JPA 是規格,Hibermate, TopLink, OpenJPA 都是 JPA 的實作。目前以 Hibernate 為 Java 最流行的 JPA framework。
Spring Data JPA 底層也是使用 Hibernate,最後透過 JDBC 連接資料庫。
spring-boot-starter-data-jpa 自動設定了 JPA,自動設定類別是
JpaRepositoriesAutoConfiguration
HibernateJpaAutoConfiguration
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-community-dialects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
application.yml
spring:
application:
name: data2
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost/testweb
username: root
password: password
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
# dialect: org.hibernate.dialect.MySQLDialect
dialect: org.hibernate.community.dialect.MySQLLegacyDialect
傳統的 JPA 必需要設定 persistence.xml,但在 spring boot 不需要。
Entity class 只需要有 @Entity
,@SpringBootApplication
或是 @EnableAutoConfiguration
就會自動掃描所有 @Entity
Data2Application 直接啟動即可
@SpringBootApplication
public class Data2Application {
public static void main(String[] args) {
SpringApplication.run(Data2Application.class, args);
}
}
UserController.java
package com.test.data2.controller;
import com.test.data2.entity.UserDO;
import com.test.data2.repo.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserRepository userRepository;
@GetMapping("/user/info/{id}")
public UserDO getUserInfo(@PathVariable("id") long id){
UserDO userDO = userRepository.findById(id).orElseGet(null);
return userDO;
}
}
UserRepository.java
package com.test.data2.repo;
import com.test.data2.entity.UserDO;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<UserDO, Long> {
}
UserDO.java
package com.test.data2.entity;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@Entity(name = "user")
public class UserDO implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String phone;
@Column(name = "create_time", nullable = false)
private Date createTime;
@Column(nullable = false)
private Integer status;
}
啟動後,可從網址 http://localhost:8080/user/info/2 取得 userid = 2 的資料
console 會出現 sql
Hibernate: select ud1_0.id,ud1_0.create_time,ud1_0.phone,ud1_0.status,ud1_0.username from user ud1_0 where ud1_0.id=?
note:
如果掃描不到,可加上 @EntityScan
指定 package/class
Spring data JPA 的 db operation 稱為 repository
org.springframework.data.repository.CrudRepository
org.springframework.data.repository.ListCrudRepository
org.springframework.data.repository.ListPagingRepository
org.springframework.data.repository.PagingAndSortingRepository
org.springframework.data.repository.kotlin.*
org.springframework.data.repository.reactive.*
UserRepository interface 會被自動掃描到,在 controller 能自動注入使用
MyBatis
MyBatis是一個Java持久化框架,它通過 XML 或 annotation 把物件與儲存程序或SQL語句關聯起來,對映成資料庫內對應的 record。
MyBatis-Plus 是 MyBatis 的封裝。
Redis
REmote DIctionary Server: Redis,是一種 key-value 的 NoSQL memory database。通常用在 cache 資料。
spring-boot-starter-data-redis
org.springframework.boot.autoconfigure.AutoConfiguration.imports 有註冊幾個自動設定類別
RedisAutoConfiguration
RedisReactiveAutoConfiguration
RedisRepositoriesAutoConfiguration
RedisAutoConfiguration 對應的參數綁定類別是 RedisProperties
在 application.yml 設定即可使用
spring:
application:
name: data3
data:
redis:
host: localhost
port: 6379
database: 0
password: password
# client-type: jedis
RedisTemplate
有兩個預設的模板可直接使用
RedisTemplate
可處理 <Object, Object>
StringRedisTemplate
只能處理 <String, String> 的資料,預設使用 JDK 的 serializer
因為 StringRedisTemplate 繼承自 RedisTemplate,必須設定兩個 RedisTemplate,所以要搭配 @ConditionalOnSingleCandidate
注入
RedisTemplate 提供的 interface:
interface | desc |
---|---|
GeoOperations | 地理空間 |
HashOperations | Hash data |
HyperLogLogOperations | HyperLogLog |
ListOperations | List |
SetOperations | Set |
ValueOperations | String |
ZSetOperations | Ordered Set |
設定 pom.xml,要加上 spring-boot-starter-integration, spring-integration-redis
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
要新增一個連線,注入 StringRedisTemplate 使用
package com.test.data3;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
public class RedisController2 {
private final StringRedisTemplate stringRedisTemplate;
@RequestMapping("/redis2/set")
public String set(@RequestParam("name") String name, @RequestParam("value") String value) {
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set(name, value);
return valueOperations.get(name);
}
}
呼叫網址 http://localhost:8080/redis2/set?name=test&value=12345 ,就會設定一個 redis key,可使用 redis-cli 檢查
> redis-cli -a password
127.0.0.1:6379> keys *
1) "test"
127.0.0.1:6379> get test
"12345"
也可以直接注入對應的 RedisTemplate 使用 valueOperations
@RequiredArgsConstructor
@RestController
public class RedisController3 {
// private final StringRedisTemplate stringRedisTemplate;
@Resource(name = "stringRedisTemplate")
private ValueOperations<String, String> valueOperations;
@RequestMapping("/redis3/set")
public String set(@RequestParam("name") String name, @RequestParam("value") String value) {
valueOperations.set(name, value);
return valueOperations.get(name);
}
}
自訂 RedisTemplate
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
StringRedisSerializer stringSerializer = new StringRedisSerializer();
RedisSerializer jacksonSerializer = getJacksonSerializer();
template.setKeySerializer(stringSerializer);
template.setValueSerializer(jacksonSerializer);
template.setHashKeySerializer(stringSerializer);
template.setHashValueSerializer(jacksonSerializer);
template.setEnableTransactionSupport(true);
template.afterPropertiesSet();
return template;
}
private RedisSerializer getJacksonSerializer() {
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL);
return new GenericJackson2JsonRedisSerializer(om);
}
}
這裡 key 使用了 StringRedisSerializer, value 使用了 GenericJackson2JsonRedisSerializer
以下是幾個常用的 serializer
serializer | desc |
---|---|
StringRedisSerializer | String/byte[] 轉換器 |
JdkSerializationRedisSerializer | JDK serializer |
OxmSerializer | XML serializer |
Jackson2JsonRedisSerializer | JSON serializer, 需要定義 JavaType |
GenericJackson2JsonRedisSerializer | JSON serializer, 不需要定義 JavaType |
MongoDB
springboot 提供兩種 starter
spring-boot-starter-data-mongodb
spring-boot-starter-data-mongodb-reactive
首先修改 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
在 org.springframework.boot.autoconfigure.AutoConfiguration.imports 註冊了幾個自動設定類別
MongoDataAutoConfiguration
MongoReactiveDataAutoConfiguration
MongoRepositoriesAutoConfiguration
MongoAutoConfiguration
MongoReactiveAutoConfiguration
設定 application.yml
spring:
data:
mongodb:
uri: mongodb://localhost:27017/test
使用 mongoTemplate
@RequiredArgsConstructor
@RestController
public class MongoController {
public static final String COLLECTION_NAME = "test";
private final MongoTemplate mongoTemplate;
@RequestMapping("/mongo/insert")
public User insert(@RequestParam("name") String name, @RequestParam("sex") int sex) {
// add
User user = new User(RandomUtils.nextInt(), name, sex);
mongoTemplate.insert(user, COLLECTION_NAME);
// query
Query query = new Query(Criteria.where("name").is(name));
return mongoTemplate.findOne(query, User.class, COLLECTION_NAME);
}
}
新增 User.java
package com.test.data4;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.mongodb.core.mapping.Document;
@NoArgsConstructor
@AllArgsConstructor
@Data
@Document(collection = "test")
public class User {
private long id;
private String name;
private int sex;
}
發送網址 http://localhost:8080/mongo/insert?name=test&sex=1
就會 insert 一筆資料到 mongodb collection: test
/* 1 */
{
"_id" : NumberLong(708252679),
"name" : "test",
"sex" : 1,
"_class" : "com.test.data4.User"
}
MongoRepository
新增 UserRepository
package com.test.data4;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
public interface UserRepository extends MongoRepository<User, Long> {
List<User> findByName(String name);
}
修改 MongoController.java
private final UserRepository userRepository;
@RequestMapping("/mongo/insert2")
public User repoInsert(@RequestParam("name") String name, @RequestParam("sex") int sex) {
// add
User user = new User(RandomUtils.nextInt(), name, sex);
userRepository.save(user);
// query
return userRepository.findByName(name).get(0);
}
發送網址 http://localhost:8080/mongo/insert2?name=test2&sex=1
就會新增 test2
Elasticsearch
springboot 支援3種客戶端
Elasticsearch 官方 REST 客戶端
Elasticsearch 官方 Java API Client
spring data elasticsearch 提供的 ReactiveElasticsearchClient
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
在 org.spingframework.boot.autoconfigure.AutoConfiguration.imports 註冊了
ElasticsearchDataAutoConfiguration
ElasticsearchRepositoriesAutoConfiguration
ReactiveElasticsearchRepositoriesAutoConfiguration
ElasticsearchClientAutoConfiguration
ElasticsearchRestClientAutoConfiguration
ReactiveElasticsearchClientAutoConfiguration
參數綁定 ElasticsearchProperties
參數 spring.elasticsearch.*
application.yml
spring:
elasticsearch:
uris: http://localhost:9200
connection-timeout: 5s
socket-timeout: 10s
username: elastic
password: password
這邊是用關閉 xpack,使用 http 的方式連線
改用 https 可參考
ref: spring-boot-starter-data-elasticsearch es带x-pack后台配置 - 微信公众号-醉鱼Java - 博客园
使用 ElasticsearchTemplate
EsController.java
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
public class EsController {
public static final String INDEX_JAVA = "java";
private final ElasticsearchTemplate elasticsearchTemplate;
@RequestMapping("/es/insert")
public User insert(@RequestParam("name") String name, @RequestParam("sex") int sex) throws InterruptedException {
// add
User user = new User(RandomUtils.nextInt(), name, sex);
IndexCoordinates indexCoordinates = IndexCoordinates.of(INDEX_JAVA);
User save = elasticsearchTemplate.save(user, indexCoordinates);
// delay and query
Thread.sleep(1000l);
Query query = new CriteriaQuery(Criteria.where("name").is(name));
return elasticsearchTemplate.searchOne(query, User.class, indexCoordinates).getContent();
}
}
User.java
@NoArgsConstructor
@AllArgsConstructor
@Data
@Document(indexName = "java")
public class User {
private long id;
private String name;
private int sex;
}
使用 UserRepository
修改 EsController.java
private final UserRepository userRepository;
@RequestMapping("/es/repo/insert")
public User repoInsert(@RequestParam("name") String name, @RequestParam("sex") int sex) {
// add
User user = new User(RandomUtils.nextInt(), name, sex);
userRepository.save(user);
// query
return userRepository.findByName(name).get(0);
}
UserRepository.java
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
public interface UserRepository extends ElasticsearchRepository<User, Long> {
List<User> findByName(String name);
}
程式跟 MongoDB 類似
沒有留言:
張貼留言