Hibernate主键生成策略

项目搭建

首先搭建一个基础项目进行策略

pom.xml

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
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.idea360</groupId>
<artifactId>spring-boot-hibernate</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-hibernate</name>
<description>Application to integrate Spring Boot with Hibernate</description>

<properties>
<java.version>1.8</java.version>
</properties>

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

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

配置mysql数据库

1
2
3
4
5
6
7
#spring.jpa.generate-ddl=true
spring.datasource.url=jdbc:mysql://localhost:3306/spring-boot-hibernate?useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

数据库初始化

通过如下配置即可自动创建表

1
2
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update

这里DDL先手动配置为主键自增类型, 后续测试不自增下的情形

1
2
3
4
5
6
7
8
9
10
DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`created_time` datetime(6) NOT NULL,
`email` varchar(255) DEFAULT NULL,
`first_name` varchar(255) DEFAULT NULL,
`last_name` varchar(255) DEFAULT NULL,
`updated_time` datetime(6) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;

创建JPA entity类

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
package cn.idea360.data;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@EntityListeners(AuditingEntityListener.class)
public class Customer {

@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String email;

@Column(updatable = false, nullable = false)
@CreatedDate
private LocalDateTime createdTime;

@Column(nullable = false)
@LastModifiedDate
private LocalDateTime updatedTime;

public Customer() {
}

public Customer(String firstName, String lastName, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}

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

public Long getId() {
return id;
}


public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public LocalDateTime getCreatedTime() {
return createdTime;
}

public void setCreatedTime(LocalDateTime createdTime) {
this.createdTime = createdTime;
}

public LocalDateTime getUpdatedTime() {
return updatedTime;
}

public void setUpdatedTime(LocalDateTime updatedTime) {
this.updatedTime = updatedTime;
}

@Override
public String toString() {
return "Customer{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}

创建Repository

1
2
3
4
5
6
7
package cn.idea360.repository;

import cn.idea360.data.Customer;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CustomerRepository extends JpaRepository<Customer,Long> {
}

创建Service

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
package cn.idea360.service;

import cn.idea360.data.Customer;
import cn.idea360.dto.CustomerData;
import cn.idea360.repository.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.EntityNotFoundException;
import java.util.ArrayList;
import java.util.List;

@Service("customerService")
public class DefaultCustomerService implements CustomerService{

@Autowired
private CustomerRepository customerRepository;

/**
* Create a customer based on the data sent to the service class.
* @param customer
* @return DTO representation of the customer
*/
@Override
public CustomerData saveCustomer(CustomerData customer) {
Customer customerModel = populateCustomerEntity(customer);
return populateCustomerData(customerRepository.save(customerModel));
}

/**
* Delete customer based on the customer ID.We can also use other option to delete customer
* based on the entoty (passing JPA entity class as method parameter)
* @param customerId
* @return boolean flag indicating the request status
*/
@Override
public boolean deleteCustomer(Long customerId) {
customerRepository.deleteById(customerId);
return true;
}

/**
* Method to return list of all the available customers in the system.This is a simple
* implementation but you might want to use pagination in the real world example.
* @return list of customer
*/
@Override
public List<CustomerData> getAllCustomers() {
List<CustomerData> customers = new ArrayList<>();
List<Customer> customerList = customerRepository.findAll();
customerList.forEach(customer -> {
customers.add(populateCustomerData(customer));
});
return customers;
}

/**
* Get customer by ID.The service will send the customer data else will throw the exception.
* @param customerId
* @return CustomerData
*/
@Override
public CustomerData getCustomerById(Long customerId) {
return populateCustomerData( customerRepository.findById(customerId).orElseThrow(() -> new EntityNotFoundException("Customer not found")));
}

/**
* Internal method to convert Customer JPA entity to the DTO object
* for frontend data
* @param customer
* @return CustomerData
*/
private CustomerData populateCustomerData(final Customer customer){
CustomerData customerData = new CustomerData();
customerData.setId(customer.getId());
customerData.setFirstName(customer.getFirstName());
customerData.setLastName(customer.getLastName());
customerData.setEmail(customer.getEmail());
return customerData;
}

/**
* Method to map the frontend customer object to the JPA customer entity.
* @param customerData
* @return Customer
*/
private Customer populateCustomerEntity(CustomerData customerData){
Customer customer = new Customer();
customer.setFirstName(customerData.getFirstName());
customer.setLastName(customerData.getLastName());
customer.setEmail(customerData.getEmail());
return customer;
}
}

创建Controller

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
package cn.idea360.controller;

import cn.idea360.dto.CustomerData;
import cn.idea360.service.CustomerService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("/customers")
public class CustomerController {

@Resource(name = "customerService")
private CustomerService customerService;

/**
* <p>Get all customer data in the system.For production system you many want to use
* pagination.</p>
* @return List<CustomerData>
*/
@GetMapping
public List<CustomerData> getCustomers(){
return customerService.getAllCustomers();
}

/**
* Method to get the customer data based on the ID.
* @param id
* @return CustomerData
*/
@GetMapping("/customer/{id}")
public CustomerData getCustomer(@PathVariable Long id){
return customerService.getCustomerById(id);
}

/**
* Post request to create customer information int the system.
* @param customerData
* @return
*/
@PostMapping("/customer")
public CustomerData saveCustomer(final @RequestBody CustomerData customerData){
return customerService.saveCustomer(customerData);
}

/**
* Delete customer from the system based on the ID. The method mapping is similar to the getCustomer with difference of
* @DeleteMapping and @GetMapping
* @param id
* @return
*/
@DeleteMapping("/customer/{id}")
public Boolean deleteCustomer(@PathVariable Long id){
return customerService.deleteCustomer(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
package cn.idea360;

import cn.idea360.data.Customer;
import cn.idea360.repository.CustomerRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing
public class SpringBootHibernateApplication {

private static final Logger log = LoggerFactory.getLogger(SpringBootHibernateApplication.class);

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

/*@Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {

repository.save(new Customer("Umesh", "Awasthi","email@test.com"));
repository.save(new Customer("David", "Dobrik", "email1@test.com"));
repository.save(new Customer("Robert", "Hickle","r.k@email.com"));
repository.save(new Customer("Edgar", "Smith","edgar@email.com"));

// fetch all customers

for (Customer customer : repository.findAll()) {
log.info(customer.toString());
}
};
}*/
}

单元测试

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
package cn.idea360;

import cn.idea360.data.Customer;
import cn.idea360.repository.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
* @author cuishiying
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CRUDTest {

@Resource
private CustomerRepository customerRepository;

@Test
public void add() {
Customer customer = new Customer();
customer.setId(7L);
customer.setFirstName("cui");
customer.setLastName("shiying");
customer.setEmail("idea360@foxmail.com");
Customer save = customerRepository.save(customer);
System.out.println(save.getId());
}
}

开启sql打印

1
2
3
4
5
6
7
8
9
10
#Statitcs and SQL logs
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.generate_statistics=true

#Enable this section based on your preferences
#logging.level.org.hibernate.type=trace
#logging.level.org.hibernate.stat=debug

logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n

ID策略测试1

前提

  • DDL中ID AUTO_INCREMENT
  • Entity给ID赋值

IDENTITY

1
2
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
1
主键由数据库自动生成, 自增

AUTO

1
2
@Id
@GeneratedValue(strategy= GenerationType.AUTO)

数据库会生成1张表 hibernate_sequence, ID自增, 从1开始.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> select * from hibernate_sequence;
+----------+
| next_val |
+----------+
| 3 |
+----------+
1 row in set (0.00 sec)

mysql> desc hibernate_sequence;
+----------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------+------+-----+---------+-------+
| next_val | bigint(20) | YES | | NULL | |
+----------+------------+------+-----+---------+-------+
1 row in set (0.01 sec)

如果id已存在, 则报错, 如下

1
Duplicate entry '1' for key 'PRIMARY'

assigned

1
2
3
@Id
@GeneratedValue(generator = "userGenerator")
@GenericGenerator(name = "userGenerator", strategy = "assigned")
1
ID由程序生成, 即实体中的ID

TABLE

1
2
3
4
5
6
7
8
9
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "table-generator")
@TableGenerator(name = "table-generator",
table = "dep_ids",
pkColumnName = "table_name",
valueColumnName = "seq_value",
pkColumnValue = "customer",
allocationSize = 1)

seq table ddl

1
2
3
4
5
6
7
DROP TABLE IF EXISTS `dep_ids`;
CREATE TABLE dep_ids(
`id` int NOT NULL AUTO_INCREMENT,
`table_name` varchar(200) NOT NULL,
`seq_value` bigint NOT NULL,
PRIMARY KEY (`id`)
);
1
Duplicate entry '1' for key 'PRIMARY'
1
2
3
4
5
6
7
mysql> select * from dep_ids;
+----+------------+-----------+
| id | table_name | seq_value |
+----+------------+-----------+
| 1 | customer | 1 |
+----+------------+-----------+
1 row in set (0.00 sec)

hibernate内置主键生成策略

org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public DefaultIdentifierGeneratorFactory() {
register( "uuid2", UUIDGenerator.class );
register( "guid", GUIDGenerator.class ); // can be done with UUIDGenerator + strategy
register( "uuid", UUIDHexGenerator.class ); // "deprecated" for new use
register( "uuid.hex", UUIDHexGenerator.class ); // uuid.hex is deprecated
register( "assigned", Assigned.class );
register( "identity", IdentityGenerator.class );
register( "select", SelectGenerator.class );
register( "sequence", SequenceStyleGenerator.class );
register( "seqhilo", SequenceHiLoGenerator.class );
register( "increment", IncrementGenerator.class );
register( "foreign", ForeignGenerator.class );
register( "sequence-identity", SequenceIdentityGenerator.class );
register( "enhanced-sequence", SequenceStyleGenerator.class );
register( "enhanced-table", TableGenerator.class );
}

自定义雪花算法生成策略

1
2
3
@Id
@GeneratedValue(generator = "snowFlakeId")
@GenericGenerator(name = "snowFlakeId", strategy = "cn.idea360.generate.SnowballIdGenerator")

雪花算法实现

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
package cn.idea360.generate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Random;

/**
* @author cuishiying
*/
public class SnowballIdWorker {

private static final Logger LOG = LoggerFactory.getLogger(SnowballIdWorker.class);

protected final long twepoch = 1288834974657L;

// |--- unused[1] ---|--- timestamp[41] ---|--- worker[10] ---|--- sequence[12] ---|
private final long workerIdBits = 10L;
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long sequenceBits = 12L;

private final long workerIdShift = sequenceBits;
private final long timestampLeftShift = sequenceBits + workerIdBits;
private final long sequenceMask = -1L ^ (-1L << sequenceBits);

protected long workerId = 0;

protected long sequence = 0L;
private long lastTimestamp = -1L;

{
byte[] address;
try {
address = InetAddress.getLocalHost().getAddress();
} catch (UnknownHostException e) {
address = null;
}
// Worker id is generated by hashing of ip address which is unique in a local network, or random if unavailable.
if (address != null) {
for (byte x : address) {
workerId = ((workerId << 8) - Byte.MIN_VALUE + x) & maxWorkerId;
}
} else {
LOG.warn("Cannot get ip address for generating server id, use random address instead.");
workerId = new Random().nextLong() & maxWorkerId;
}
LOG.info("Worker starting. Timestamp left shift {}, worker id bits {}, sequence bits {}, worker id {}.",
timestampLeftShift, workerIdBits, sequenceBits, workerId);
}

protected synchronized long nextId() {
long timestamp = timeGen();

if (timestamp < lastTimestamp) {
LOG.error("Clock is moving backwards. Rejecting requests until {}.", lastTimestamp);
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - timestamp));
}

if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}

lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
}

protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}

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

ID生成策略实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package cn.idea360.generate;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;

import java.io.Serializable;

/**
* @author cuishiying
*/
public class SnowballIdGenerator implements IdentifierGenerator {

private final SnowballIdWorker worker = new SnowballIdWorker();

@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
return worker.nextId();
}
}
1
ID由算法生成雪花ID并成功插入

自定义多级ID生成策略

  1. 如果入参ID有值, 则按id值入库
  2. 如果入参ID==null, 则按table写入

首先我们初始化ddl后开始测试, 分别测试id为空, id有值的场景

1
2
3
4
5
6
7
8
9
@Id
@GeneratedValue(generator = "id_gen")
@GenericGenerator(name = "id_gen", strategy = "cn.idea360.generate.CustomGenerator",
parameters = {
@Parameter( name = "table_name", value = "enhanced_gen"),
@Parameter( name ="value_column_name", value = "next"),
@Parameter( name = "segment_column_name",value = "segment_name"),
@Parameter( name = "increment_size", value = "1")
})

enhanced_gen会自动生成

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
package cn.idea360.generate;

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.enhanced.TableGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;

import java.io.Serializable;
import java.util.Properties;

/**
* @author cuishiying
*/
public class CustomGenerator extends TableGenerator implements Configurable {

private String entityName;

@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
entityName = params.getProperty(ENTITY_NAME);
if (entityName == null) {
throw new MappingException("no entity name");
}
params.setProperty(TableGenerator.SEGMENT_VALUE_PARAM, params.getProperty(JPA_ENTITY_NAME));
super.configure(type, params, serviceRegistry);
}

@Override
public Serializable generate(SharedSessionContractImplementor session, Object obj) throws HibernateException {
final Serializable id = session.getEntityPersister(entityName, obj).getIdentifier(obj, session);
if (id == null) {
return super.generate(session, obj);
}
return id;
}
}

自定义多级ID生成策略2(补充)

  1. 如果入参ID有值, 则按id值入库
  2. 如果入参ID==null, 则按Identity写入
1
2
3
4
5
@Id
@Column(name = "id")
@GeneratedValue(generator = CustomIdentityGenerator.CUSTOM_IDENTITY_GENERATOR)
@GenericGenerator(name = CustomIdentityGenerator.CUSTOM_IDENTITY_GENERATOR, strategy = CustomIdentityGenerator.CUSTOM_IDENTITY_STRATEGY)
public Long 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
public class CustomIdentityGenerator extends IdentityGenerator implements Configurable {

public static final String CUSTOM_IDENTITY_GENERATOR = "custom_identity";

public static final String CUSTOM_IDENTITY_STRATEGY = "org.ueom.eom.data.generator.CustomIdentityGenerator";

private String entityName;

@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
entityName = params.getProperty(ENTITY_NAME);
if (entityName == null) {
throw new MappingException("no entity name");
}
params.setProperty(TableGenerator.SEGMENT_VALUE_PARAM, params.getProperty("target_table"));
}

@Override
public Serializable generate(SharedSessionContractImplementor session, Object obj) throws HibernateException {
final Serializable id = session.getEntityPersister(entityName, obj).getIdentifier(obj, session);
if (id == null || (id instanceof Number && 0L == ((Number)id).longValue())) {
return super.generate(session, obj);
}
return id;
}
}

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
mysql> show tables;
+---------------------------------+
| Tables_in_spring-boot-hibernate |
+---------------------------------+
| customer |
| enhanced_gen |
+---------------------------------+
2 rows in set (0.00 sec)

mysql> desc enhanced_gen;
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| segment_name | varchar(255) | NO | PRI | NULL | |
| next | bigint(20) | YES | | NULL | |
+--------------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> select * from enhanced_gen;
+--------------+------+
| segment_name | next |
+--------------+------+
| customer | 2 |
+--------------+------+
1 row in set (0.00 sec)
mysql> select * from customer;
+----+----------------------------+---------------------+------------+-----------+----------------------------+
| id | created_time | email | first_name | last_name | updated_time |
+----+----------------------------+---------------------+------------+-----------+----------------------------+
| 1 | 2023-04-25 08:49:31.707081 | idea360@foxmail.com | cui | shiying | 2023-04-25 08:49:31.707081 |
| 2 | 2023-04-25 08:52:08.651403 | idea360@foxmail.com | cui | shiying | 2023-04-25 08:52:08.651403 |
+----+----------------------------+---------------------+------------+-----------+----------------------------+
2 rows in set (0.00 sec)

ID赋值测试

1
2
3
4
5
6
7
8
9
mysql> select * from customer;
+----+----------------------------+---------------------+------------+-----------+----------------------------+
| id | created_time | email | first_name | last_name | updated_time |
+----+----------------------------+---------------------+------------+-----------+----------------------------+
| 1 | 2023-04-25 08:49:31.707081 | idea360@foxmail.com | cui | shiying | 2023-04-25 08:49:31.707081 |
| 2 | 2023-04-25 08:52:08.651403 | idea360@foxmail.com | cui | shiying | 2023-04-25 08:52:08.651403 |
| 7 | 2023-04-25 08:54:14.444484 | idea360@foxmail.com | cui | shiying | 2023-04-25 08:54:14.444484 |
+----+----------------------------+---------------------+------------+-----------+----------------------------+
3 rows in set (0.00 sec)

ID策略测试2

前提

  • DDL中ID不自增
  • Entity给ID赋值

IDENTITY

@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
1
Field 'id' doesn't have a default value

AUTO

@Id
@GeneratedValue(strategy= GenerationType.AUTO)
1
ID由hibernate_sequence控制, 从1开始

assigned

@Id
@GeneratedValue(generator = "userGenerator")
@GenericGenerator(name = "userGenerator", strategy = "assigned")
1
ID由程序生成, 即实体中的ID

TABLE

@Id
@GeneratedValue(strategy = GenerationType.TABLE,
        generator = "table-generator")
@TableGenerator(name = "table-generator",
        table = "dep_ids",
        pkColumnName = "table_name",
        valueColumnName = "seq_value",
        pkColumnValue = "customer",
        allocationSize = 1)
1
Duplicate entry '1' for key 'PRIMARY'

自定义主键生成策略

@Id
@GeneratedValue(generator = "snowFlakeId")
@GenericGenerator(name = "snowFlakeId", strategy = "cn.idea360.generate.SnowballIdGenerator")
1
ID由算法生成雪花ID并成功插入

参考