在 pom.xml 文件中添加依赖:
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
由于使用 HikariCP 连接池,添加下面依赖:
<dependency>
<groupId>com.zaxxergroupId>
<artifactId>HikariCPartifactId>
dependency>
在 application.yml 文件中添加配置:
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password:
type: com.zaxxer.hikari.HikariDataSource
jpa:
database: mysql
database-platform: MYSQL
show-sql: true
format-sql: true
hibernate:
ddl-auto: update
naming:
strategy: org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
编写配置类:
import com.mj.wcs.domain.User;
import com.mj.wcs.repository.UserRepository;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author smileorsilence
* @date 2018/03/28
*/
@Configuration
@EntityScan(basePackageClasses = User.class)
@EnableJpaRepositories(basePackageClasses = UserRepository.class)
@EnableTransactionManagement
public class HibernateJpaConfiguration {
}
编写实体类:
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* @author smileorsilence
*/
@Data
@Entity
@Table(name = "user")
public class User implements Serializable {
@Id
@GeneratedValue
private Long id;
@NotNull
@Column(name = "username")
private String username;
@NotNull
@JsonIgnore
@Column(name = "password")
private String password;
@Column(name = "email", unique = true)
private String email;
}
编写Repository类:
import com.mj.wcs.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
/**
* @author smileorsilence
* @date 2018/03/28
*/
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional findOneByEmail(String email);
}
编写Service类:
import com.mj.wcs.domain.User;
import com.mj.wcs.repository.UserRepository;
import com.mj.wcs.service.util.MD5Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.inject.Inject;
/**
* @author smileorsilence
* @date 2018/03/28
*/
@Slf4j
@Service
@Transactional
public class UserService {
@Inject
private UserRepository userRepository;
public User saveUser() {
User user = new User();
user.setUsername("爱他明月好");
user.setPassword(MD5Util.encodeByMD5("憔悴也相关"));
user = userRepository.save(user);
log.info("saveUser, user : {}", user);
return user;
}
}
编写Controller类:
import com.mj.wcs.domain.User;
import com.mj.wcs.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.inject.Inject;
/**
* @author smileorsilence
* @date 2018/03/28
*/
@Api("test")
@Slf4j
@Controller
@RequestMapping("/api")
public class UserController {
@Inject
private UserService userService;
@ApiOperation(value = "测试saveUser方法")
@RequestMapping(value = "/user/save", method = RequestMethod.GET)
@ResponseBody
public User saveUser() {
log.info("saveUser");
return userService.saveUser();
}
}
运行程序,抛出异常:
2018-03-28 16:47:37.032 ERROR 1744 --- [ main] o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
... ? common frames omitted
Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:264) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
... ? common frames omitted
Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException: Unable to resolve name [MYSQL] as strategy [org.hibernate.dialect.Dialect]
at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.selectStrategyImplementor(StrategySelectorImpl.java:113) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
... ? common frames omitted
定位异常原因是 application.yml 配置文件中 JPA 配置错误:
spring:
jpa:
database-platform: MYSQL
修改为如下:
spring:
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
抛出异常:
2018-03-28 18:10:00.899 ERROR 7904 --- [ main] o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:954) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
... ? common frames omitted
Caused by: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Unknown database 'nmgyj-wcs'
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:512) ~[HikariCP-2.5.1.jar:na]
... ? common frames omitted
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown database 'nmgyj-wcs'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_111]
... ? common frames omitted
定位异常原因是 MySQL 数据库中找不到 nmgyj-wcs 数据库错误:
创建对应数据库即可。
使用Postman测试:
编写Junit单元测试:
import com.mj.wcs.domain.User;
import com.mj.wcs.repository.UserRepository;
import com.mj.wcs.service.util.MD5Util;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.inject.Inject;
/**
* @author smileorsilence
* @date 2018/03/28
*/
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserServiceTest {
@Inject
private UserRepository userRepository;
@Test
public void saveUser() throws Exception {
User user = new User();
user.setUsername("爱他明月好");
user.setPassword(MD5Util.encodeByMD5("憔悴也相关"));
user.setEmail("[email protected]");
user = userRepository.save(user);
log.info("saveUser, user : {}", user);
}
}
运行测试方法,抛出异常:
2018-03-28 19:25:49.669 INFO 8324 --- [ main] com.mj.wcs.service.UserServiceTest : Started UserServiceTest in 15.072 seconds (JVM running for 16.826)
Hibernate:
select
next_val as id_val
from
hibernate_sequence for update
Hibernate:
update
hibernate_sequence
set
next_val= ?
where
next_val=?
Hibernate:
insert
into
user
(email, password, username, id)
values
(?, ?, ?, ?)
2018-03-28 19:25:50.003 WARN 8324 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1062, SQLState: 23000
2018-03-28 19:25:50.003 ERROR 8324 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Duplicate entry '1' for key 'PRIMARY'
2018-03-28 19:25:50.006 INFO 8324 --- [ main] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
... ? more
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
... ? more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1' for key 'PRIMARY'
... ? more
定位异常原因可能是 User 实体类中使用 Lombok 提供的 @Data 注解导致 equals() 方法和 hashCode() 方法重写不正确,使用 IDEA 重新生成即可。
定位异常原因可能是数据库中 hibernate_sequence 这张表中 next_val 这列的值重复所导致。