SpringBoot整合ORM:
使用JPA规范:
源码分析:
public class SpringImplicitNamingStrategy extends ImplicitNamingStrategyJpaCompliantImpl {
@Override
public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) {
String name = source.getOwningPhysicalTableName() + "_"
+ source.getAssociationOwningAttributePath().getProperty();
return toIdentifier(name, source.getBuildingContext());
}
}
JTA 事务:
public class SpringJtaPlatform extends AbstractJtaPlatform {
private static final long serialVersionUID = 1L;
private final JtaTransactionManager transactionManager;
public SpringJtaPlatform(JtaTransactionManager transactionManager) {
Assert.notNull(transactionManager, "TransactionManager must not be null");
this.transactionManager = transactionManager;
}
@Override
protected TransactionManager locateTransactionManager() {
return this.transactionManager.getTransactionManager();
}
@Override
protected UserTransaction locateUserTransaction() {
return this.transactionManager.getUserTransaction();
}
}
实体工厂的Enttity:
public class EntityManagerFactoryBuilder {
private final JpaVendorAdapter jpaVendorAdapter;
private final PersistenceUnitManager persistenceUnitManager;
private final Map<String, Object> jpaProperties;
private final URL persistenceUnitRootLocation;
private AsyncTaskExecutor bootstrapExecutor;
private PersistenceUnitPostProcessor[] persistenceUnitPostProcessors;
/**
* Create a new instance passing in the common pieces that will be shared if multiple
* EntityManagerFactory instances are created.
* @param jpaVendorAdapter a vendor adapter
* @param jpaProperties the JPA properties to be passed to the persistence provider
* @param persistenceUnitManager optional source of persistence unit information (can
* be null)
*/
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter, Map<String, ?> jpaProperties,
PersistenceUnitManager persistenceUnitManager) {
this(jpaVendorAdapter, jpaProperties, persistenceUnitManager, null);
}
/**
* Create a new instance passing in the common pieces that will be shared if multiple
* EntityManagerFactory instances are created.
* @param jpaVendorAdapter a vendor adapter
* @param jpaProperties the JPA properties to be passed to the persistence provider
* @param persistenceUnitManager optional source of persistence unit information (can
* be null)
* @param persistenceUnitRootLocation the persistence unit root location to use as a
* fallback (can be null)
* @since 1.4.1
*/
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter, Map<String, ?> jpaProperties,
PersistenceUnitManager persistenceUnitManager, URL persistenceUnitRootLocation) {
this.jpaVendorAdapter = jpaVendorAdapter;
this.persistenceUnitManager = persistenceUnitManager;
this.jpaProperties = new LinkedHashMap<>(jpaProperties);
this.persistenceUnitRootLocation = persistenceUnitRootLocation;
}
public Builder dataSource(DataSource dataSource) {
return new Builder(dataSource);
}
/**
* Configure the bootstrap executor to be used by the
* {@link LocalContainerEntityManagerFactoryBean}.
* @param bootstrapExecutor the executor
* @since 2.1.0
*/
public void setBootstrapExecutor(AsyncTaskExecutor bootstrapExecutor) {
this.bootstrapExecutor = bootstrapExecutor;
}
/**
* Set the {@linkplain PersistenceUnitPostProcessor persistence unit post processors}
* to be applied to the PersistenceUnitInfo used for creating the
* {@link LocalContainerEntityManagerFactoryBean}.
* @param persistenceUnitPostProcessors the persistence unit post processors to use
* @since 2.5.0
*/
public void setPersistenceUnitPostProcessors(PersistenceUnitPostProcessor... persistenceUnitPostProcessors) {
this.persistenceUnitPostProcessors = persistenceUnitPostProcessors;
}
/**
* A fluent builder for a LocalContainerEntityManagerFactoryBean.
*/
public final class Builder {
private DataSource dataSource;
private PersistenceManagedTypes managedTypes;
private String[] packagesToScan;
private String persistenceUnit;
private Map<String, Object> properties = new HashMap<>();
private String[] mappingResources;
private boolean jta;
private Builder(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* The persistence managed types, providing both the managed entities and packages
* the entity manager should consider.
* @param managedTypes managed types.
* @return the builder for fluent usage
*/
public Builder managedTypes(PersistenceManagedTypes managedTypes) {
this.managedTypes = managedTypes;
return this;
}
/**
* The names of packages to scan for {@code @Entity} annotations.
* @param packagesToScan packages to scan
* @return the builder for fluent usage
* @see #managedTypes(PersistenceManagedTypes)
*/
public Builder packages(String... packagesToScan) {
this.packagesToScan = packagesToScan;
return this;
}
/**
* The classes whose packages should be scanned for {@code @Entity} annotations.
* @param basePackageClasses the classes to use
* @return the builder for fluent usage
* @see #managedTypes(PersistenceManagedTypes)
*/
public Builder packages(Class<?>... basePackageClasses) {
Set<String> packages = new HashSet<>();
for (Class<?> type : basePackageClasses) {
packages.add(ClassUtils.getPackageName(type));
}
this.packagesToScan = StringUtils.toStringArray(packages);
return this;
}
/**
* The name of the persistence unit. If only building one EntityManagerFactory you
* can omit this, but if there are more than one in the same application you
* should give them distinct names.
* @param persistenceUnit the name of the persistence unit
* @return the builder for fluent usage
*/
public Builder persistenceUnit(String persistenceUnit) {
this.persistenceUnit = persistenceUnit;
return this;
}
/**
* Generic properties for standard JPA or vendor-specific configuration. These
* properties override any values provided in the constructor.
* @param properties the properties to use
* @return the builder for fluent usage
*/
public Builder properties(Map<String, ?> properties) {
this.properties.putAll(properties);
return this;
}
/**
* The mapping resources (equivalent to {@code <mapping-file>} entries in
* {@code persistence.xml}) for the persistence unit.
* <p>
* Note that mapping resources must be relative to the classpath root, e.g.
* "META-INF/mappings.xml" or "com/mycompany/repository/mappings.xml", so that
* they can be loaded through {@code ClassLoader.getResource()}.
* @param mappingResources the mapping resources to use
* @return the builder for fluent usage
*/
public Builder mappingResources(String... mappingResources) {
this.mappingResources = mappingResources;
return this;
}
/**
* Configure if using a JTA {@link DataSource}, i.e. if
* {@link LocalContainerEntityManagerFactoryBean#setDataSource(DataSource)
* setDataSource} or
* {@link LocalContainerEntityManagerFactoryBean#setJtaDataSource(DataSource)
* setJtaDataSource} should be called on the
* {@link LocalContainerEntityManagerFactoryBean}.
* @param jta if the data source is JTA
* @return the builder for fluent usage
*/
public Builder jta(boolean jta) {
this.jta = jta;
return this;
}
public LocalContainerEntityManagerFactoryBean build() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
if (EntityManagerFactoryBuilder.this.persistenceUnitManager != null) {
entityManagerFactoryBean
.setPersistenceUnitManager(EntityManagerFactoryBuilder.this.persistenceUnitManager);
}
if (this.persistenceUnit != null) {
entityManagerFactoryBean.setPersistenceUnitName(this.persistenceUnit);
}
entityManagerFactoryBean.setJpaVendorAdapter(EntityManagerFactoryBuilder.this.jpaVendorAdapter);
if (this.jta) {
entityManagerFactoryBean.setJtaDataSource(this.dataSource);
}
else {
entityManagerFactoryBean.setDataSource(this.dataSource);
}
if (this.managedTypes != null) {
entityManagerFactoryBean.setManagedTypes(this.managedTypes);
}
else {
entityManagerFactoryBean.setPackagesToScan(this.packagesToScan);
}
entityManagerFactoryBean.getJpaPropertyMap().putAll(EntityManagerFactoryBuilder.this.jpaProperties);
entityManagerFactoryBean.getJpaPropertyMap().putAll(this.properties);
if (!ObjectUtils.isEmpty(this.mappingResources)) {
entityManagerFactoryBean.setMappingResources(this.mappingResources);
}
URL rootLocation = EntityManagerFactoryBuilder.this.persistenceUnitRootLocation;
if (rootLocation != null) {
entityManagerFactoryBean.setPersistenceUnitRootLocation(rootLocation.toString());
}
if (EntityManagerFactoryBuilder.this.bootstrapExecutor != null) {
entityManagerFactoryBean.setBootstrapExecutor(EntityManagerFactoryBuilder.this.bootstrapExecutor);
}
if (EntityManagerFactoryBuilder.this.persistenceUnitPostProcessors != null) {
entityManagerFactoryBean.setPersistenceUnitPostProcessors(
EntityManagerFactoryBuilder.this.persistenceUnitPostProcessors);
}
return entityManagerFactoryBean;
}
}
}
JpaDatabaseInitializerDetector:
class JpaDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {
private final Environment environment;
JpaDatabaseInitializerDetector(Environment environment) {
this.environment = environment;
}
@Override
protected Set<Class<?>> getDatabaseInitializerBeanTypes() {
boolean deferred = this.environment.getProperty("spring.jpa.defer-datasource-initialization", boolean.class,
false);
return deferred ? Collections.singleton(EntityManagerFactory.class) : Collections.emptySet();
}
@Override
public void detectionComplete(ConfigurableListableBeanFactory beanFactory, Set<String> dataSourceInitializerNames) {
configureOtherInitializersToDependOnJpaInitializers(beanFactory, dataSourceInitializerNames);
}
private void configureOtherInitializersToDependOnJpaInitializers(ConfigurableListableBeanFactory beanFactory,
Set<String> dataSourceInitializerNames) {
Set<String> jpaInitializers = new HashSet<>();
Set<String> otherInitializers = new HashSet<>(dataSourceInitializerNames);
Iterator<String> iterator = otherInitializers.iterator();
while (iterator.hasNext()) {
String initializerName = iterator.next();
BeanDefinition initializerDefinition = beanFactory.getBeanDefinition(initializerName);
if (JpaDatabaseInitializerDetector.class.getName()
.equals(initializerDefinition.getAttribute(DatabaseInitializerDetector.class.getName()))) {
iterator.remove();
jpaInitializers.add(initializerName);
}
}
for (String otherInitializerName : otherInitializers) {
BeanDefinition definition = beanFactory.getBeanDefinition(otherInitializerName);
String[] dependencies = definition.getDependsOn();
for (String dependencyName : jpaInitializers) {
dependencies = StringUtils.addStringToArray(dependencies, dependencyName);
}
definition.setDependsOn(dependencies);
}
}
}
*/
class JpaDependsOnDatabaseInitializationDetector extends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {
private final Environment environment;
JpaDependsOnDatabaseInitializationDetector(Environment environment) {
this.environment = environment;
}
@Override
protected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {
boolean postpone = this.environment.getProperty("spring.jpa.defer-datasource-initialization", boolean.class,
false);
return postpone ? Collections.emptySet()
: new HashSet<>(Arrays.asList(EntityManagerFactory.class, AbstractEntityManagerFactoryBean.class));
}
}
JPA–Java 持久层 API:
Spring Data 是 Spring 的一个子项目,旨在统一和简化各类型数据的持久化存储方式,而不拘泥于是关系型数据库还是NoSQL数据库。
无论是哪种持久化存储方式,DAO(Data Access Objects,数据访问对象) 都会提供对对象的增加、删除、修饰和查询的方法,以及排序和分页方法等。
Spring Data 提供了基于这些层面的统一接口(如:CrudRepository、PageingAndSortingRepository),以实现持久化的存储。
使用:使用 JPA:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL 数据库 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.配置数据库连接信息
3.hibernate的配置属性参数值列表:
none : 启动时不做任何操作。默认值,什么都不做,每次启动项目,不会对数据库进行任何验证和操作。
create :每次加载 Hibernate 时都会删除上一次生成的表,然后根据 Model 类再重新生成新表,哪怕没有任何改变也会这样执行,这会导致数据库数据的丢失。(每次加载 Hibernate,重新创建数据库表结构)
create-drop :每次加载 Hibernate 时会根据 Model 类生成表,但是 sessionFactory 一旦关闭,表就会自动被删除。(加载 Hibernate 时创建,退出是删除表结构)
update :最常用的属性。第一次加载 Hibernate 时会根据 Model 类自动建立表的结构(前提是先建立好数据库)。以后加载 Hibernate 时,会根据 Model 类自动更新表结构,即使表结构改变了,但表中的数据仍然存在,不会被删除。要注意的是,当部署到服务器后,表结构是不会被马上建立起来的,要等应用程序第一次运行起来后才会建立。update 表示如果 Entity 实体的字段发生了变化,那么直接在数据库中进行更新。(加载 Hibernate 时自动更新数据库结构)
validate :每次加载 Hibernate 时,会验证数据库的表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。(加载 Hibernate 时,验证创建数据库表结构)
JPA 的常用注解:
@Entity :标识实体类是JPA实体,告诉JPA在程序运行时生成实体类对应表
@Table :设置实体类在数据库所对应的表名
@Id :标识类里所在变量为主键
@GeneratedValue :设置主键生成策略,此方式依赖于具体的数据库
@Column :表示属性所对应字段名进行个性化设置
@Transient :表示属性并非数据库表字段的映射,ORM框架将忽略该属性
@CreatedDate :表示字段为创建时间字段(insert自动设置)
@CreatedBy :表示字段为创建用户字段(insert自动设置),通过实现 “AuditorAware” 接口的 “getCurrentAuditor” 方法来实现赋值。
懒加载 LAZY 和 实时加载 EAGER:
懒加载 LAZY 和 实时加载 EAGER 的目的是,实现关联数据的选择性加载。
懒加载是在属性被引用时才生成查询语句,抽取相关数据。
实时加载则是执行完主查询后,不管是否被引用,都会马上执行后续的关联数据查询
使用懒加载来调用关联数据,必须要保证主查询的 session(数据库连接会话)的生命周期没有结束,否则无法抽取到数据的。
映射关系注解:
@JoinColumn :指定一个实体组织或实体集合。用在“多对一”和“一对多”的关联中。
@OneToOne :定义表之间“一对一”的关系
@OneToMany :定义表之间“一对多”的关系
@ManyToOne :定义表之间“多对一”的关系
@ManyToMany :定义表之间“多对多”的关系
————————————————
认识 JPA 的接口
JPA 提供了操作数据库的接口。在开发过程中继承和使用这些接口,可简化现有的持久化开发工作。
JPA 接口 JpaRepository
JpaRepository 继承自 PaingAndSortingRepository 。该接口提供了 JPA 的相关实用功能,以及通过 Example 进行查询的功能。 Example 对象是 JPA 提供用来构造查询条件的对象。
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>,
QueryByExampleExecutor {
}
1
2
3
4
在上述代码中, T 表示实体对象, ID 表示主键。 ID 必须实现序列化。
分页排序接口 PagingAndSortingRepository
PagingAndSortingRepository 继承自 CrudRepository 提供的分页和排序方法。
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable findAll(Sort var1);
Page<T> findAll(Pageable var1);
}
1
2
3
4
5
findAll(Sort sort) :排序功能。它按照 “sort” 制定的排序返回数据。
Page findAll(Pageable pageable) :分页查询(含排序功能)。