初学Spring-data-jpa+jpa配置+Springboot和Spring-data-jpa做简单操作+分布式服务设置一个永远不重复的ID

关于Spring-data-jpa的配置+Springboot+Spring-data-jpa的简单操作+分布式服务设置一个永远不重复的ID

初学Spring全家桶家族中的Spring-data-jpa发现可以更简单的实现一些基本的增删改查,以下是一些基础操作,希望可以给初学者一些帮助。

spring家族
Spring Boot
spring Cloud
Spring framework
Spring-data
Spring data-jpa(简单的增删改查)
...
1
2
3
4
5
6
jpa配置
jpa的底层是基于hibernate
多表联查的时候会用到一对多,多对一的关系等

springboot一旦是一个web程序,记得配置数据源
1
2
3
4


springdata-jpa一般是不需要自己写sql语句的
springdata-jpa.hibernate.ddl-auto:update/create
如果是使用create:每次都会新建一个对应的表,覆盖原有的表
update:不会覆盖原有的表,只会更新表结构和表数据
当没有设置驼峰命名的时候,默认会以gradeId---->grade_id
1
2
3
4
5

具体代码如下:

#springboot数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/studentjpa?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
password: root
username: root
#配置spring-data-jpa
jpa:
show-sql: true #控制台输出sql语句
database: mysql #jpa使用的数据库
hibernate:
ddl-auto: update
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

server:
port: 8081
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
实体类快速建表
Spring Data Jpa 可以根据实体类 在数据库里自动生成表
实体类的注解
@Data 自动封装属性
@Table(name = "student") 对应数据库中的表,用于指定表的名称
@Entity 注解用于生成数据库表,
1
2
3
4


Id列的注解
@Id 表示这是一个主键。
@GeneratedValue(strategy = )用于根据规则生成主键,
/*Id表示主键 主键有生成策略*/
/*GenerationType.IDENTITY唯一列还自动增长*/
/*GenerationType.AUTO自动增长*/
/*Oracle中是没有自动增长的 设置GenerationType.SEQUENCE 使用序列进行增长*/
/*GeneratedValue 自动增长生成的value值*/
1
2
3
4
5
6
7
8


普通列注解
@Column
1
2

启动后自动建表成功


Dao(数据访问层)接口
DAO的接口:
继承JpaRepository<Student,Integer>, JpaSpecificationExecutor<Student>
JpaRepository 扩展简单的增删改查、批量操作
JpaSpecificationExecutor 用来做负责查询的接口
其他:
Repository 空接口
CrudRepository 增删改查
PagingAndSortingRepository 分页和排序
Specification 是Spring Data JPA提供的一个查询规范,要做复杂的查询,类似hibernate QBC查询

JpaRepository继承PagingAndSortingRepository,CrudRepository:
CrudRepository 提供 save、 delete、 deteleAll、 findAll、 findOne、 count等方法
PagingAndSortingRepository提供排序及分页findAll(Sort) (基于排序的查询)、findAll(Pageable)( 基于分页的查询)
1
2
3
4
5
6
7
8
9
10
11
12
13

Dao层代码

package com.szh.springdatajpa.dao;

import com.szh.springdatajpa.pojo.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

/**
* 学生数据访问层
*
* @author 宋政宏
* @date 2019-05-17
*/
public interface StudentDao extends JpaRepository<Student,Integer>, JpaSpecificationExecutor<Student> {

/*nativeQuery 原声的sql语句查询*/
/*根据姓名模糊查询*/
@Query(value = "select * from student where name like concat('%',?,'%')",nativeQuery = true)
List<Student> selByName(String name);

/*查询前两行信息*/
List<Student> findTop2By();

/*根据姓名模糊查询*/
List<Student> findByNameContaining(String name);


/*根据姓名或性别模糊查询*/
//List<Student> findByNameLikeOrSexNotIn()

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Service层(实现层)的接口和类
interface接口

Service接口中有新增,修改,查询,根据id查询,根据id删除,根据姓名模糊查询,查询前俩行信息,模糊查询,分页查询等方法
1

 

package com.szh.springdatajpa.service;

import com.szh.springdatajpa.pojo.Student;
import org.springframework.data.domain.Page;

import java.util.List;


/**
* 学生实现层接口
*
* @author 宋政宏
* @date 2019-05-17
*/
public interface StudentService {

/*新增学生信息*/
Student add(Student student);

/*修改学生信息*/
Student upd(Student student);

/*查询所有学生信息*/
List<Student>selAll();

/*根据id查询学生信息*/
Student selById(Integer id);

/*根据id删除学生信息*/
String del(Integer id);

/*根据姓名模糊查询*/
List<Student> selByName(String name);

/*查询前俩行信息*/
List<Student> findTop2();

/*模糊查询*/
List<Student> findByNameLike(String name);

/*分页查询*/
Page<Student> findByPage(Integer pageNum, Integer size);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Impl类

 

package com.szh.springdatajpa.service.impl;

import com.szh.springdatajpa.dao.StudentDao;
import com.szh.springdatajpa.pojo.Student;
import com.szh.springdatajpa.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
* 学生实现类
*
* @author 宋政宏
* @date 2019-05-17
*/
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao studentDao;
/*新增学生信息*/
@Override
public Student add(Student student) {
Student add = studentDao.save(student);
return add;
}

/*修改学生信息*/
@Override
public Student upd(Student student) {
//有id的时候是修改,没有id的时候是新增
Student upd = studentDao.save(student);
return upd;
}

/*查询所有学生信息*/
@Override
public List<Student> selAll() {
List<Student> sa = studentDao.findAll();
return sa;
}

/*根据id查询学生信息*/
@Override
public Student selById(Integer id) {
Optional<Student> selbyid = studentDao.findById(id);
return selbyid.get();
}

/*根据id删除学生信息*/
@Override
public String del(Integer id) {
studentDao.deleteById(id);
return "删除成功";
}
/*根据姓名模糊查询*/
@Override
public List<Student> selByName(String name) {
return studentDao.selByName(name);
}
/*查询前两条信息*/
@Override
public List<Student> findTop2(){
return studentDao.findTop2By();
}
/*模糊查询*/
@Override
public List<Student> findByNameLike(String name){
return studentDao.findByNameContaining(name);
}
/*分页查询*/
@Override
public Page<Student> findByPage(Integer pageNum,Integer size){
PageRequest pageRequest = PageRequest.of(pageNum - 1, size);
return studentDao.findAll(pageRequest);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Controller(控制层)类
@RestController:@Controller+@ResponseBody 以json数据进行返回
1


package com.szh.springdatajpa.controller;

import com.szh.springdatajpa.pojo.Student;
import com.szh.springdatajpa.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
*学生控制层
*
* @author 宋政宏
* @date 2019-05-17
*/
@RestController
public class StudentController {

@Autowired
private StudentService studentService;

/**
* 新增学生信息
* @param student
* @return
*/
@PostMapping("/student")
public Student add(Student student){
return studentService.add(student);
}
/**
* 修改学生信息
* @param student
* @return
*/
@PutMapping("/update")
public Student upd(Student student){
return studentService.upd(student);
}
/**
* 查询所有学生信息
* @param
* @return
*/
@GetMapping("/selAll")
public List<Student> selAll(){
return studentService.selAll();
}

/**
* 根据id查询学生信息
* @param id
* @return
*/
@GetMapping("/selById/{id}")
public Student selById(@PathVariable("id")Integer id){
return studentService.selById(id);
}
/**
* 删除学生信息
* @param id
* @return
*/
@DeleteMapping("/delete/{id}")
public String delete(@PathVariable("id") Integer id){
return studentService.del(id);
}

/**
* 根据姓名模糊查询
*
* @param name
* @return
*/
@GetMapping("/selByName")
public List<Student> selByName(String name){
return studentService.selByName(name);
}
/**
* 查询前两行学生信息
*
* @param
* @return
*/
@GetMapping("/findTop2")
public List<Student> findTop2(){
return studentService.findTop2();
}
/**
* 模糊查询
*
* @param
* @return
*/
@GetMapping("/findByNameLike")
public List<Student> findByNameLike(String name){
return studentService.findByNameLike(name);
}
@GetMapping("/findByPage")
public List<Student> findByPage(Integer pageNum,Integer size){
Page<Student> page = studentService.findByPage(pageNum, size);
//return "总条数是"+page.getTotalElements();
return page.getContent();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
最后运行项目打开Postman工具测试功能!

查询成功!

设置一个永远不重复的ID
解决高并发id的问题
UUID 分布式服务自己设置Id
1
2
SpringdatajpaApplication运行类自定义Bean属性

 

/*自定义Bean属性*/
@Bean
public IdWorker idWorker(){
return new IdWorker(1,1);
}

1
2
3
4
5
6
新建util包创建IdWorker类

IdWorker类的代码:

package com.changan.springdatajpa.util;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;

/**
* <p>名称:IdWorker.java</p>
* <p>描述:分布式自增长ID</p>
* <pre>
* Twitter的 Snowflake JAVA实现方案
* </pre>
* 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
* 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
* 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
* 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
* 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
* 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
* <p>
* 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
*
* @author Polim
*/
public class IdWorker {
// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
private final static long twepoch = 1288834974657L;
// 机器标识位数
private final static long workerIdBits = 5L;
// 数据中心标识位数
private final static long datacenterIdBits = 5L;
// 机器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private final static long sequenceBits = 12L;
// 机器ID偏左移12位
private final static long workerIdShift = sequenceBits;
// 数据中心ID左移17位
private final static long datacenterIdShift = sequenceBits + workerIdBits;
// 时间毫秒左移22位
private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/* 上次生产id时间戳 */
private static long lastTimestamp = -1L;
// 0,并发控制
private long sequence = 0L;

private final long workerId;
// 数据标识id部分
private final long datacenterId;

public IdWorker(){
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
* @param workerId
* 工作机器ID
* @param datacenterId
* 序列号
*/
public IdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 获取下一个ID
*
* @return
*/
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}

if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
long nextId = ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;

return nextId;
}

private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}

private long timeGen() {
return System.currentTimeMillis();
}

/**
* <p>
* 获取 maxWorkerId
* </p>
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuffer mpid = new StringBuffer();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
/*
* GET jvmPid
*/
mpid.append(name.split("@")[0]);
}
/*
* MAC + PID 的 hashcode 获取16个低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}

/**
* <p>
* 数据标识id部分
* </p>
*/
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
} catch (Exception e) {
System.out.println(" getDatacenterId: " + e.getMessage());
}
return id;
}


}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
然后修改上面Service层(实现层)的Impl类

这是Impl类中新增Id处理
1


最后大功告成,运行项目。

 


---------------------

posted @ 2019-07-13 02:09  李艳艳665  阅读(561)  评论(0编辑  收藏  举报