文章目录
前言
当前版本mysql8.0.15
父pom
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>jdbc</module>
<module>mybatis</module>
<module>jpa</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>sql</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sql</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<!--开启全局依赖管理-->
<dependencyManagement></dependencyManagement>
<dependencies>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<!--对应数据库版本号-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
JDBC
SpringBoot整合jdbc
jdbc.pom
<parent>
<artifactId>sql</artifactId>
<groupId>com.example</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jdbc</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
application.properties
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=123456
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://localhost:3306/learn2020?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
DataSource装载
@Configuration
@ConditionalOnClass(DruidDataSource.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
@Import({DruidSpringAopConfiguration.class,
DruidStatViewServletConfiguration.class,
DruidWebStatFilterConfiguration.class,
DruidFilterConfiguration.class})
public class DruidDataSourceAutoConfigure {
private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);
@Bean(initMethod = "init")
@ConditionalOnMissingBean
public DataSource dataSource() {
LOGGER.info("Init DruidDataSource");
return new DruidDataSourceWrapper();
}
}
jdbcTemplate的装载
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(JdbcOperations.class)
class JdbcTemplateConfiguration {
@Bean
@Primary
JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
JdbcProperties.Template template = properties.getTemplate();
jdbcTemplate.setFetchSize(template.getFetchSize());
jdbcTemplate.setMaxRows(template.getMaxRows());
if (template.getQueryTimeout() != null) {
jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
}
return jdbcTemplate;
}
}
自定义类
public class User {
private Integer id;
private String username;
private String password;
}
@Service
public class UserService {
JdbcTemplate jdbcTemplate;
public UserService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public boolean addUser(User user) {
int update = jdbcTemplate.update("insert into USER (username,password) values (?,?);",
user.getUsername(), user.getPassword());
if (update > 0) return true;
return false;
}
public boolean updateUserById(User user) {
int update = jdbcTemplate.update("update user set username = ?,password=? where id=? ;",
user.getUsername(), user.getPassword(), user.getId());
if (update > 0) return true;
return false;
}
public boolean deleteUserById(User user) {
int update = jdbcTemplate.update("delete from user where id=?;",
user.getId());
if (update > 0) return true;
return false;
}
public List<User> selectUser() {
List<User> result = (List<User>) jdbcTemplate.query("select * from USER", (rs, rowNum) -> {
return new User(rs.getInt("id"),
rs.getString("username"),
rs.getString("password"));
});
if (result != null) return result;
return null;
}
//需要数据库表和对象字段名称一一对应
public List<User> selectUser2() {
List<User> result = jdbcTemplate.query("select * from USER", new BeanPropertyRowMapper<>(User.class));
if (result != null) return result;
return null;
}
//自定义行映射
public List<User> selectUserById(User user) {
List<User> result = jdbcTemplate.query("select * from USER where id=?;", (rs, rowNum) -> {
return new User(rs.getInt("id"),
rs.getString("username"),
rs.getString("password"));
}, user.getId());
if (result != null) return result;
return null;
}
}
测试
@SpringBootTest
public class JdbcTest {
@Autowired
UserService userService;
@Test
public void selectUser() {
System.out.println(new ArrayList<>(userService.selectUser()).toString());
}
}
2020-12-09 14:39:19.190 INFO 6800 --- [ main] com.example.JdbcTest : Started JdbcTest in 2.688 seconds (JVM running for 4.299)
[User{id=1, username='root1', password='1234561'}, User{id=3, username='root2', password='1234562'}, User{id=4, username='root2', password='1234562'}]
2020-12-09 14:39:20.515 INFO 6800 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
JDBC多数据源
配置多个数据源
application.properties
spring.datasource.first.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.first.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.first.password=123456
spring.datasource.first.username=root
spring.datasource.first.url=jdbc:mysql://localhost:3306/learn2020?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.second.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.second.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.second.password=123456
spring.datasource.second.username=root
spring.datasource.second.url=jdbc:mysql://localhost:3306/learn2020_1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
DatabaseConfig
@Configuration
public class DatabaseConfig {
//为bean属性赋值指定属性绑定前缀
@Bean
@ConfigurationProperties(prefix = "spring.datasource.first")
DataSource first() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.second")
DataSource second() {
return DruidDataSourceBuilder.create().build();
}
}
JdbcTempleConfig
@Configuration
public class JdbcTemplateConfig {
@Bean(name = "jdbcFirst")
JdbcTemplate first(@Qualifier("first") DataSource first) {
return new JdbcTemplate(first);
}
@Bean(name = "jdbcSecond")
JdbcTemplate second(@Qualifier("second") DataSource second) {
return new JdbcTemplate(second);
}
}
UserServiceMulti
@Service
public class UserServiceMulti {
JdbcTemplate first;
JdbcTemplate second;
public UserServiceMulti(@Qualifier("jdbcFirst") JdbcTemplate first,
@Qualifier("jdbcSecond") JdbcTemplate second) {
this.first = first;
this.second = second;
}
public List<User> selectFirst() {
return first.query("select * from user", new BeanPropertyRowMapper<>(User.class));
}
public List<User> selectSecond() {
return second.query("select * from user", new BeanPropertyRowMapper<>(User.class));
}
}
Test
@Test
public void selectMulti() {
System.out.println(new ArrayList<>(multi.selectFirst()).toString());
System.out.println(new ArrayList<>(multi.selectSecond()).toString());
}
2020-12-09 15:07:54.292 INFO 14484 --- [ main] com.example.JdbcTest : Started JdbcTest in 2.266 seconds (JVM running for 3.405)
2020-12-09 15:07:54.630 INFO 14484 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
[User{id=1, username='root1', password='1234561'}, User{id=3, username='root2', password='1234562'}, User{id=4, username='root2', password='1234562'}]
2020-12-09 15:07:55.631 INFO 14484 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} inited
[User{id=1, username='database2', password='1'}, User{id=2, username='database2', password='2'}]
2020-12-09 15:07:55.671 INFO 14484 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
Mybatis
SpringBoot整合Mybatis
mybatis.pom
<parent>
<artifactId>sql</artifactId>
<groupId>com.example</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mybatis</artifactId>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
application.properties
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=123456
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://localhost:3306/learn2020?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
启动类
@SpringBootApplication
//定义mapper.xml扫描包
@MapperScan(basePackages = "com.example.service")
public class MybatisApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisApplication.class,args);
}
}
interface
package com.example.service;
public interface UserMapper {
List<User> getAllUser();
}
bean
public class User {
private Integer id;
private String username;
private String password;
UserMapper.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="com.example.service.UserMapper">
<select id="getAllUser" resultType="com.example.bean.User">
select * from user
</select>
</mapper>
装配
/**Register bean definitions as necessary based on the given annotation
*metadata of the importing @Configuration class.
*Note that BeanDefinitionRegistryPostProcessor types may not be
*registered here, due to lifecycle constraints related to
*@Configuration
*class processing.
*The default implementation is empty.
*/
org.mybatis.spring.annotation.MapperScannerRegistrar#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry)
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
generateBaseBeanName(importingClassMetadata, 0));
}
}
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
applyConfiguration(factory);
if (this.properties.getConfigurationProperties() != null) {
factory.setConfigurationProperties(this.properties.getConfigurationProperties());
}
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (this.properties.getTypeAliasesSuperType() != null) {
factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.typeHandlers)) {
factory.setTypeHandlers(this.typeHandlers);
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
Set<String> factoryPropertyNames = Stream
.of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors()).map(PropertyDescriptor::getName)
.collect(Collectors.toSet());
Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
// Need to mybatis-spring 2.0.2+
factory.setScriptingLanguageDrivers(this.languageDrivers);
if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
defaultLanguageDriver = this.languageDrivers[0].getClass();
}
}
if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
// Need to mybatis-spring 2.0.2+
factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
}
return factory.getObject();
}
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
}
test
@SpringBootTest
public class example {
@Autowired
UserMapper userMapper;
@Test
public void selectOrigin(){
System.out.println(userMapper.getAllUser());
}
2020-12-09 16:09:57.601 INFO 8600 --- [ main] com.example.example : Started example in 15.602 seconds (JVM running for 17.097)
[User{id=1, username='root1', password='1234561'}, User{id=3, username='root2', password='1234562'}, User{id=4, username='root2', password='1234562'}]
2020-12-09 16:09:58.959 INFO 8600 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closing ...
2020-12-09 16:09:58.963 INFO 8600 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closed
Mybatis多数据源
application.properties
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.one.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.one.password=123456
spring.datasource.one.username=root
spring.datasource.one.url=jdbc:mysql://localhost:3306/learn2020?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.two.password=123456
spring.datasource.two.username=root
spring.datasource.two.url=jdbc:mysql://localhost:3306/learn2020_1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
MybatisMultiConfig
@Configuration
@MapperScans(
{
@MapperScan(basePackages = "com.example.mapper1", sqlSessionFactoryRef = "sqlSessionFactory1",
sqlSessionTemplateRef = "sqlSessionTemplate1"),
@MapperScan(basePackages = "com.example.mapper2", sqlSessionFactoryRef = "sqlSessionFactory2",
sqlSessionTemplateRef = "sqlSessionTemplate2")
}
)
public class MybatisMultiConfig {
@Bean
@ConfigurationProperties("spring.datasource.one")
DataSource first() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.two")
DataSource second() {
return DruidDataSourceBuilder.create().build();
}
@Bean
SqlSessionFactory sqlSessionFactory1(@Qualifier("first") DataSource first) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(first);
return bean.getObject();
}
@Bean
SqlSessionTemplate sqlSessionTemplate1(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean
SqlSessionFactory sqlSessionFactory2(@Qualifier("second") DataSource second) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(second);
return bean.getObject();
}
@Bean
SqlSessionTemplate sqlSessionTemplate2(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
test
@SpringBootTest
public class example {
@Autowired
UserMapper1 userMapper1;
@Autowired
UserMapper2 userMapper2;
@Test
public void selectMulti(){
System.out.println(userMapper1.getAllUser());
System.out.println(userMapper2.getAllUser());
}
}
2020-12-09 16:23:29.815 INFO 3096 --- [ main] com.example.example : Started example in 2.801 seconds (JVM running for 4.004)
2020-12-09 16:23:30.163 INFO 3096 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
[User{id=1, username='root1', password='1234561'}, User{id=3, username='root2', password='1234562'}, User{id=4, username='root2', password='1234562'}]
2020-12-09 16:23:31.374 INFO 3096 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} inited
[User{id=1, username='database2', password='1'}, User{id=2, username='database2', password='2'}]
2020-12-09 16:23:31.411 INFO 3096 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
2020-12-09 16:23:31.412 INFO 3096 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closing ...
2020-12-09 16:23:31.414 INFO 3096 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closed
2020-12-09 16:23:31.415 INFO 3096 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closing ...
2020-12-09 16:23:31.415 INFO 3096 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closed
JPA
SpringBoot整合Jpa
jpa.pom
<parent>
<artifactId>sql</artifactId>
<groupId>com.example</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jpa</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
application.properties
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=123456
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://localhost:3306/learn2020?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
#展示每次操作生成的sql语句
spring.jpa.show-sql=true
#spring.jpa.database=mysql
#spring.jpa.database-platform=mysql
#只有不存在或者修改后才创建修改表
spring.jpa.hibernate.ddl-auto=update
#确认默认引擎是innodb而不MyISAM
#hibernate.dialect.storage_engine=innodb
#AvailableSettings.DIALECT
#通过AvailableSettings设置hibernate的可用的配置
#如下配置是表明操作的数据库是mysql,数据库引擎为innodb而不是myisam
#org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
Entity
//标注为一个实体(是一个表)
@Entity
public class Book {
//标注这个字段是主键ID
@Id
//配置主键生成策略
//GenerationType.IDENTITY表示自增ID
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String author;
接口
public interface BookService extends JpaRepository<Book, Integer> {
//下面所有为自定义查询方法
Book findBookById(Integer id);
List<Book> findBookByIdGreaterThan(Integer id);
@Query(value = "select * from Book where id=(select max(id) from Book )", nativeQuery = true)
Book getMaxIdBook();
//对于表的修改操作必须添加事务才能操作
//?1按照方法顺序查询参数
@Query(value = "insert into Book(name,author) values(?1,?2)", nativeQuery = true)
@Modifying
@Transactional
Integer addBook(String name, String author);
//:会自动查询@Param参数
@Query(value = "insert into Book(name,author) values(:name,:author)", nativeQuery = true)
@Modifying
@Transactional
Integer addBook1(@Param("name")String name,@Param("author") String author);
}
RepositoryBaseClass装载
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(DataSource.class)
@ConditionalOnClass(JpaRepository.class)
@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class, JpaRepositoryConfigExtension.class })
@ConditionalOnProperty(prefix = "spring.data.jpa.repositories", name = "enabled", havingValue = "true",
matchIfMissing = true)
@Import(JpaRepositoriesRegistrar.class)
@AutoConfigureAfter({ HibernateJpaAutoConfiguration.class, TaskExecutionAutoConfiguration.class })
public class JpaRepositoriesAutoConfiguration {
}
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration
@EnableJpaRepositories
private static class EnableJpaRepositoriesConfiguration {
}
org.springframework.data.jpa.repository.config.EnableJpaRepositories#repositoryFactoryBeanClass
Class<?> repositoryFactoryBeanClass() default JpaRepositoryFactoryBean.class;
org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean#afterPropertiesSet
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
}
org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#afterPropertiesSet
public void afterPropertiesSet() {
this.factory = createRepositoryFactory();
this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey);
this.factory.setNamedQueries(namedQueries);
this.factory.setEvaluationContextProvider(
evaluationContextProvider.orElseGet(() -> QueryMethodEvaluationContextProvider.DEFAULT));
this.factory.setBeanClassLoader(classLoader);
this.factory.setBeanFactory(beanFactory);
if (publisher != null) {
this.factory.addRepositoryProxyPostProcessor(new EventPublishingRepositoryProxyPostProcessor(publisher));
}
repositoryBaseClass.ifPresent(this.factory::setRepositoryBaseClass);
RepositoryFragments customImplementationFragment = customImplementation //
.map(RepositoryFragments::just) //
.orElseGet(RepositoryFragments::empty);
RepositoryFragments repositoryFragmentsToUse = this.repositoryFragments //
.orElseGet(RepositoryFragments::empty) //
.append(customImplementationFragment);
this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface);
// Make sure the aggregate root type is present in the MappingContext (e.g. for auditing)
this.mappingContext.ifPresent(it -> it.getPersistentEntity(repositoryMetadata.getDomainType()));
this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse));
if (!lazyInit) {
this.repository.get();
}
}
org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryInformation(org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.repository.core.support.RepositoryComposition)
private RepositoryInformation getRepositoryInformation(RepositoryMetadata metadata,
RepositoryComposition composition) {
RepositoryInformationCacheKey cacheKey = new RepositoryInformationCacheKey(metadata, composition);
return repositoryInformationCache.computeIfAbsent(cacheKey, key -> {
Class<?> baseClass = repositoryBaseClass.orElse(getRepositoryBaseClass(metadata));
return new DefaultRepositoryInformation(metadata, baseClass, composition);
});
}
org.springframework.data.jpa.repository.support.JpaRepositoryFactory#getRepositoryBaseClass
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return SimpleJpaRepository.class;
}
org.springframework.data.jpa.repository.support.JpaRepositoryFactory#getRepositoryBaseClass
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return SimpleJpaRepository.class;
}
配置属性设值
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class })
@EnableConfigurationProperties(JpaProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
@Import(HibernateJpaConfiguration.class)
public class HibernateJpaAutoConfiguration {
}
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration#getVendorProperties
@Override
protected Map<String, Object> getVendorProperties() {
Supplier<String> defaultDdlMode = () -> this.defaultDdlAutoProvider.getDefaultDdlAuto(getDataSource());
return new LinkedHashMap<>(this.hibernateProperties
.determineHibernateProperties(getProperties().getProperties(), new HibernateSettings()
.ddlAuto(defaultDdlMode).hibernatePropertiesCustomizers(this.hibernatePropertiesCustomizers)));
}
JpaRepository本身自带一些查询方法
具体操作通过jdk代理实现
test
@SpringBootTest
public class BookTest {
@Autowired
BookService1 bookService;
@Test
public void add(){
bookService.save(new Book("水调歌头","苏轼"));
}
@Test
public void select(){
System.out.println(bookService.findAll());
}
@Test
public void selectDesc(){
List<Book> books = bookService.findAll(Sort.by(Sort.Direction.DESC, "id"));
System.out.println(books);
}
@Test
public void selectPageable(){
Page<Book> books = bookService.findAll(PageRequest.of(1,2));
System.out.println("当前页内容"+books.getContent());
System.out.println("是否为首页"+books.isFirst());
System.out.println("是否为尾页"+books.isLast());
System.out.println("总页数"+books.getTotalPages());
System.out.println("当前页元素个数"+books.getNumberOfElements());
System.out.println("当前页下标数"+books.getNumber());
}
@Test
public void selectById(){
System.out.println(bookService.findBookById(1));
System.out.println(bookService.findBookByIdGreaterThan(2));
System.out.println(bookService.getMaxIdBook());
}
Jpa多数据源
application.properties
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.one.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.one.password=123456
spring.datasource.one.username=root
spring.datasource.one.url=jdbc:mysql://localhost:3306/learn2020?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.two.password=123456
spring.datasource.two.username=root
spring.datasource.two.url=jdbc:mysql://localhost:3306/learn2020_1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
#spring.jpa.properties.hibernate.ddl-auto无法生效
#spring.jpa.properties.hibernate.ddl-auto=update
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
JpaMultiConfig
@Configuration
public class JpaMultiConfig {
@Autowired
JpaProperties properties;
@Autowired
HibernateProperties hibernateProperties;
@Autowired
HibernateSettings settings;
@Bean
HibernateSettings settings() {
return new HibernateSettings();
}
class DatasourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.one")
@Primary
DataSource first() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.two")
DataSource second() {
return DruidDataSourceBuilder.create().build();
}
}
@EnableJpaRepositories(basePackages = "com.example.service1",
entityManagerFactoryRef = "factoryBean1",
transactionManagerRef = "transactionManager1")
class JpaConfig1 {
@Bean
@Primary
LocalContainerEntityManagerFactoryBean factoryBean1(EntityManagerFactoryBuilder builder,
@Qualifier("first") DataSource dataSource) {
return builder.dataSource(dataSource)
.properties(
hibernateProperties.determineHibernateProperties(
properties.getProperties(), settings
)
)
.packages("com.example.bean")
.persistenceUnit("jpa1")
.build();
}
@Bean
@Primary
PlatformTransactionManager transactionManager1(EntityManagerFactoryBuilder builder,
@Qualifier("factoryBean1") LocalContainerEntityManagerFactoryBean bean) {
return new JpaTransactionManager(bean.getObject());
}
}
@EnableJpaRepositories(basePackages = "com.example.service2",
entityManagerFactoryRef = "factoryBean2",
transactionManagerRef = "transactionManager2")
class JpaConfig2 {
@Bean
LocalContainerEntityManagerFactoryBean factoryBean2(EntityManagerFactoryBuilder builder,
@Qualifier("second") DataSource dataSource) {
System.out.println(new HashSet(properties.getProperties().values()).toString());
return builder.dataSource(dataSource)
.properties(
hibernateProperties.determineHibernateProperties(
properties.getProperties(), settings
)
)
.packages("com.example.bean")
.persistenceUnit("jpa2")
.build();
}
@Bean
PlatformTransactionManager transactionManager2(EntityManagerFactoryBuilder builder,
@Qualifier("factoryBean2") LocalContainerEntityManagerFactoryBean bean) {
return new JpaTransactionManager(bean.getObject());
}
}
}
test
@Autowired
BookService1 service1;
@Autowired
BookService2 service2;
@Test
public void selectMulti(){
System.out.println(service1.findAll());
System.out.println(service2.findAll());
}
Hibernate:
select
book0_.id as id1_0_,
book0_.author as author2_0_,
book0_.name as name3_0_
from
book book0_
[Book{id=1, name='三国', author='罗贯中'}, Book{id=2, name='西游记', author='吴承恩'}, Book{id=3, name='红楼梦', author='曹雪芹'}, Book{id=4, name='观沧海', author='曹操'}, Book{id=5, name='水调歌头', author='苏轼'}, Book{id=6, name='test?', author='test?'}, Book{id=7, name='test:', author='test:'}, Book{id=9, name='test?1', author='test?1'}, Book{id=10, name='test:1', author='test:1'}]
Hibernate:
select
book0_.id as id1_0_,
book0_.author as author2_0_,
book0_.name as name3_0_
from
book book0_
[]
总结
JPA数据查询方法声明规范
自定义查询通过@Query注解
例如
@Query(value = "select * from Book where id=(select max(id) from Book )", nativeQuery = true)
Book getMaxIdBook();
原生的sql需要对nativeQuery 属性赋值为true,否则默认是jpa自带的一种查询语言规范
对于表的修改操作(修改,删除,添加)必须添加事务才能操作,同时需要标注为 @Modifying,表明这是一个修改语句
@Query(value = "insert into Book(name,author) values(?1,?2)", nativeQuery = true)
@Modifying
@Transactional
否则会报错
Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
默认情况下, Spring Data 的每个方法上有事务, 但都是一个只读事务. 他们不能完成修改操作
jpa事务的注意事项:
Spring Data 提供了默认的事务处理方式,即所有的查询均声明为只读事务。
对于自定义的方法,如需改变 Spring Data 提供的事务默认方式,可以在方法上添加 @Transactional 注解。
进行多个 Repository 操作时,也应该使它们在同一个事务中处理,按照分层架构的思想,这部分属于业务逻辑层,因此,需要在Service 层实现对多个 Repository 的调用,并在相应的方法上声明事务。
@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {