第 05 章 Spring Boot 整合持久层技术

文章目录

  • 前言
  • JDBC
    • SpringBoot整合jdbc
    • JDBC多数据源
  • Mybatis
    • SpringBoot整合Mybatis
    • Mybatis多数据源
  • JPA
    • SpringBoot整合Jpa
    • Jpa多数据源
    • 总结

前言

当前版本mysql8.0.15
父pom

 
<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.0modelVersion><packaging>pompackaging><modules><module>jdbcmodule><module>mybatismodule><module>jpamodule>modules><parent><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-parentartifactId><version>2.2.11.RELEASEversion><relativePath/> parent><groupId>com.examplegroupId><artifactId>sqlartifactId><version>0.0.1-SNAPSHOTversion><name>sqlname><description>Demo project for Spring Bootdescription><properties><java.version>1.8java.version>properties><dependencyManagement>dependencyManagement><dependencies><dependency><groupId>com.alibabagroupId><artifactId>druid-spring-boot-starterartifactId><version>1.2.3version>dependency><dependency><groupId>mysqlgroupId><artifactId>mysql-connector-javaartifactId><scope>runtimescope>dependency><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-webartifactId>dependency><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-testartifactId><scope>testscope><exclusions><exclusion><groupId>org.junit.vintagegroupId><artifactId>junit-vintage-engineartifactId>exclusion>exclusions>dependency>dependencies><build><plugins><plugin><groupId>org.springframework.bootgroupId><artifactId>spring-boot-maven-pluginartifactId>plugin>plugins>build>
project>

JDBC

SpringBoot整合jdbc

jdbc.pom

    <parent><artifactId>sqlartifactId><groupId>com.examplegroupId><version>0.0.1-SNAPSHOTversion>parent><modelVersion>4.0.0modelVersion><artifactId>jdbcartifactId><dependencies><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-jdbcartifactId>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")@ConditionalOnMissingBeanpublic 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@PrimaryJdbcTemplate 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 {@AutowiredUserService userService;@Testpublic 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=UTCspring.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

    @Testpublic 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>sqlartifactId><groupId>com.examplegroupId><version>0.0.1-SNAPSHOTversion>parent><modelVersion>4.0.0modelVersion><artifactId>mybatisartifactId><dependencies><dependency><groupId>org.mybatis.spring.bootgroupId><artifactId>mybatis-spring-boot-starterartifactId><version>2.1.4version>dependency>dependencies><build><resources><resource><directory>src/main/javadirectory><includes><include>**/*.xmlinclude>includes>resource><resource><directory>src/main/resourcesdirectory>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



<mapper namespace="com.example.service.UserMapper"><select id="getAllUser" resultType="com.example.bean.User">select * from userselect>
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)@Overridepublic 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@ConditionalOnMissingBeanpublic 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@ConditionalOnMissingBeanpublic 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 {@AutowiredUserMapper userMapper;@Testpublic 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=UTCspring.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();}@BeanSqlSessionFactory sqlSessionFactory1(@Qualifier("first") DataSource first) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(first);return bean.getObject();}@BeanSqlSessionTemplate sqlSessionTemplate1(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}@BeanSqlSessionFactory sqlSessionFactory2(@Qualifier("second") DataSource second) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(second);return bean.getObject();}@BeanSqlSessionTemplate sqlSessionTemplate2(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}
}

test

@SpringBootTest
public class example {@AutowiredUserMapper1 userMapper1;@AutowiredUserMapper2 userMapper2;@Testpublic 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>sqlartifactId><groupId>com.examplegroupId><version>0.0.1-SNAPSHOTversion>parent><modelVersion>4.0.0modelVersion><artifactId>jpaartifactId><dependencies><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-data-jpaartifactId>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@TransactionalInteger addBook(String name, String author);//:会自动查询@Param参数@Query(value = "insert into Book(name,author) values(:name,:author)", nativeQuery = true)@Modifying@TransactionalInteger 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@Overridepublic void afterPropertiesSet() {super.afterPropertiesSet();}
org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#afterPropertiesSetpublic 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@Overrideprotected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {return SimpleJpaRepository.class;}org.springframework.data.jpa.repository.support.JpaRepositoryFactory#getRepositoryBaseClass@Overrideprotected 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@Overrideprotected 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 {@AutowiredBookService1 bookService;@Testpublic void add(){bookService.save(new Book("水调歌头","苏轼"));}@Testpublic void select(){System.out.println(bookService.findAll());}@Testpublic void selectDesc(){List<Book> books = bookService.findAll(Sort.by(Sort.Direction.DESC, "id"));System.out.println(books);}@Testpublic 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());}@Testpublic 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=UTCspring.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=UTCspring.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 {@AutowiredJpaProperties properties;@AutowiredHibernateProperties hibernateProperties;@AutowiredHibernateSettings settings;@BeanHibernateSettings settings() {return new HibernateSettings();}class DatasourceConfig {@Bean@ConfigurationProperties("spring.datasource.one")@PrimaryDataSource 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@PrimaryLocalContainerEntityManagerFactoryBean 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@PrimaryPlatformTransactionManager transactionManager1(EntityManagerFactoryBuilder builder,@Qualifier("factoryBean1") LocalContainerEntityManagerFactoryBean bean) {return new JpaTransactionManager(bean.getObject());}}@EnableJpaRepositories(basePackages = "com.example.service2",entityManagerFactoryRef = "factoryBean2",transactionManagerRef = "transactionManager2")class JpaConfig2 {@BeanLocalContainerEntityManagerFactoryBean 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();}@BeanPlatformTransactionManager transactionManager2(EntityManagerFactoryBuilder builder,@Qualifier("factoryBean2") LocalContainerEntityManagerFactoryBean bean) {return new JpaTransactionManager(bean.getObject());}}
}

test

    @AutowiredBookService1 service1;@AutowiredBookService2 service2;@Testpublic void selectMulti(){System.out.println(service1.findAll());System.out.println(service2.findAll());}
Hibernate: selectbook0_.id as id1_0_,book0_.author as author2_0_,book0_.name as name3_0_ frombook 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: selectbook0_.id as id1_0_,book0_.author as author2_0_,book0_.name as name3_0_ frombook 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> {


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部