![]() |
捣蛋的手术刀 · wellerman由来_百度知道· 3 月前 · |
![]() |
潇洒的茶叶 · 明年2024整个社会就进入九运时代,这是一个 ...· 1 年前 · |
![]() |
干练的煎饼果子 · linux - Ansible ...· 1 年前 · |
![]() |
忐忑的豆芽 · BuildProperties - ...· 1 年前 · |
![]() |
英姿勃勃的鸡蛋面 · 1777048 – TypeError: ...· 1 年前 · |
firstname |
https://docs.spring.io/spring-data/jpa/docs/1.5.0.RELEASE/reference/html/jpa.repositories.html |
![]() |
机灵的水龙头
1 年前 |
Using this element looks up Spring Data repositories as described
in
Section 1.2.3, “Creating repository instances”
. Beyond that it
activates persistence exception translation for all beans annotated with
@Repository
to let exceptions being
thrown by the JPA persistence providers be converted into Spring's
DataAccessException
hierarchy.
Example 2.2. Spring Data JPA repositories using JavaConfig
@Configuration @EnableJpaRepositories @EnableTransactionManagement class ApplicationConfig { @Bean public DataSource dataSource() { EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); return builder.setType(EmbeddedDatabaseType.HSQL).build(); @Bean public EntityManagerFactory entityManagerFactory() { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setGenerateDdl(true); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(vendorAdapter); factory.setPackagesToScan("com.acme.domain"); factory.setDataSource(dataSource()); factory.afterPropertiesSet(); return factory.getObject(); @Bean public PlatformTransactionManager transactionManager() { JpaTransactionManager txManager = new JpaTransactionManager(); txManager.setEntityManagerFactory(entityManagerFactory()); return txManager; }
The just shown configuration class sets up an embedded HSQL
database using the
EmbeddedDatabaseBuilder
API of
spring-jdbc. We then set up a
EntityManagerFactory
and use Hibernate as
sample persistence provider. The last infrastructure component declared
here is the
JpaTransactionManager
. We eventually
activate Spring Data JPA repositories using the
@EnableJpaRepositories
annotation which
essentially carries the same attributes as the XML namespace does. If no
base package is configured it will use the one the configuration class
resides in.
Spring Data JPA offers the following strategies to detect whether an entity is new or not:
Table 2.2. Options for detection whether an entity is new in Spring Data JPA
Id-Property inspection ( default ) |
By default Spring Data JPA inspects the Id-Property of
the given Entity. If the Id-Property is
null
,
then the entity will be assumed as new, otherwise as not
new.
|
Implementing
Persistable
|
If an entity implements the
Persistable
interface, Spring
Data JPA will delegate the new-detection to the
isNew
- Method of the Entity. See the
JavaDoc
for details.
|
Implementing
EntityInformation
|
One can customize the
EntityInformation
abstraction
used in the
SimpleJpaRepository
implementation by creating a subclass of
JpaRepositoryFactory
and overriding the
getEntityInformation
-Method
accordingly. One then has to register the custom
implementation of
JpaRepositoryFactory
as a Spring bean. Note that this should be rarely necessary.
See the
JavaDoc
for details.
|
Although getting a query derived from the method name is quite
convenient, one might face the situation in which either the method
name parser does not support the keyword one wants to use or the
method name would get unnecessarily ugly. So you can either use JPA
named queries through a naming convention (see
Section 2.3.3, “Using JPA NamedQueries”
for more information) or
rather annotate your query method with
@Query
(see
Section 2.3.4, “Using @Query”
for details).
Generally the query creation mechanism for JPA works as described in Section 1.2, “Query methods” . Here's a short example of what a JPA query method translates into:
Example 2.3. Query creation from method names
public interface UserRepository extends Repository<User, Long> { List<User> findByEmailAddressAndLastname(String emailAddress, String lastname); }
We will create a query using the JPA criteria API from this but essentially this translates into the following query:
select u from User u where u.emailAddress = ?1 and u.lastname = ?2
Spring Data JPA will do a property check and traverse nested properties as described in ??? . Here's an overview of the keywords supported for JPA and what a method containing that keyword essentially translates to.
![]() |
Note |
---|---|
|
![]() |
Note |
---|---|
The examples use simple
|
In the just shown sample
LIKE
delimiter character
%
is recognized and the query transformed into a valid
JPQL query (removing the
%
). Upon query execution the
parameter handed into the method call gets augmented with the
previously recognized
LIKE
pattern.
Of course you could have just used
User
in
the query declaration directly but that would require you to change the
query as well. The reference to
#entityName
will pick up
potential future remappings of the
User
class to
a different entity name (e.g. by using
@Entity(name =
"MyUser")
.
Another use case for the
#{#entityName}
expression in
a query string is if you want to define a generic repository interface
with specialized repository interfaces for a concrete domain type. In
order not to have to repeat the definition of custom query methods on
the concrete interfaces you can use the entity name expression in the
query string of the
@Query
annotation in the generic
repository interface.
Example 2.12. Using SpEL expressions in Repository query methods - entityName with inheritance
@MappedSuperclass public abstract class AbstractMappedType { String attribute @Entity public class ConcreteType extends AbstractMappedType { … } @NoRepositoryBean public interface MappedTypeRepository<T extends AbstractMappedType> extends Repository<T, Long> { @Query("select t from #{#entityName} t where t.attribute = ?1") List<T> findAllByAttribute(String attribute); public interface ConcreteRepository extends MappedTypeRepository<ConcreteType> { … }
In the example the interface
MappedTypeRepository
is
the common parent interface for a few domain types extending
AbstractMappedType
. It also defines the generic
method
findAllByAttribute(…)
which can be used
on instances of the specialized repository interfaces. If you now invoke
findByAllAttribute(…)
on
ConcreteRepository
the query being
executed will be
select t from ConcreteType t where t.attribute =
?1
.
All the sections above describe how to declare queries to access a
given entity or collection of entities. Of course you can add custom
modifying behaviour by using facilities described in
Section 1.3, “Custom implementations for Spring Data repositories”
. As this approach is
feasible for comprehensive custom functionality, you can achieve the
execution of modifying queries that actually only need parameter binding
by annotating the query method with
@Modifying
:
This will trigger the query annotated to the method as updating
query instead of a selecting one. As the
EntityManager
might contain outdated
entities after the execution of the modifying query, we do not
automatically clear it (see JavaDoc of
EntityManager
.
clear()
for details) since this will effectively drop all non-flushed changes
still pending in the
EntityManager
. If
you wish the
EntityManager
to be cleared
automatically you can set
@Modifying
annotation's
clearAutomatically
attribute to
true
.
public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor { }
For example, the
findAll
method will return all
entities that match the specification:
List<T> findAll(Specification<T> spec);
The
Specification
interface is as
follows:
public interface Specification<T> { Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder); }
Admittedly the amount of boilerplate leaves room for improvement
(that will hopefully be reduced by Java 8 closures) but the client side
becomes much nicer as you will see below. The
Customer_
type is a metamodel type generated using
the JPA Metamodel generator (see the
Hibernate
implementation's documentation for example
). So the expression
Customer_.createdAt
is asuming the
Customer
having a
createdAt
attribute
of type
Date
. Besides that we have expressed some
criteria on a business requirement abstraction level and created
executable
Specification
s. So a client
might use a
Specification
as
follows:
Okay, why not simply create a query for this kind of data access?
You're right. Using a single
Specification
does not gain a lot of benefit over a plain query declaration. The power
of
Specification
s really shines when you
combine them to create new
Specification
objects. You can achieve this through the
Specifications
helper class we provide to build
expressions like this:
Example 2.17. Combined Specifications
MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR); List<Customer> customers = customerRepository.findAll( where(isLongTermCustomer()).or(hasSalesOfMoreThan(amount)));
As
you can see,
Specifications
offers some glue-code
methods to chain and combine
Specification
s. Thus extending your data
access layer is just a matter of creating new
Specification
implementations and
combining them with ones already existing.
Another possibility to alter transactional behaviour is using a facade or service implementation that typically covers more than one repository. Its purpose is to define transactional boundaries for non-CRUD operations:
Example 2.19. Using a facade to define transactions for multiple repository calls
@Service class UserManagementImpl implements UserManagement { private final UserRepository userRepository; private final RoleRepository roleRepository; @Autowired public UserManagementImpl(UserRepository userRepository, RoleRepository roleRepository) { this.userRepository = userRepository; this.roleRepository = roleRepository; @Transactional public void addRoleToAllUsers(String roleName) { Role role = roleRepository.findByName(roleName); for (User user : userRepository.findAll()) { user.addRole(role); userRepository.save(user); }
This will cause call to
addRoleToAllUsers(…)
to run inside a
transaction (participating in an existing one or create a new one if
none already running). The transaction configuration at the repositories
will be neglected then as the outer transaction configuration determines
the actual one used. Note that you will have to activate
<tx:annotation-driven />
or use
@EnableTransactionManagement
explicitly
to get annotation based configuration at facades working. The example
above assumes you are using component scanning.
![]() |
Note |
---|---|
It's definitely reasonable to use transactions for read only
queries and we can mark them as such by setting the
|
To specify the lock mode to be used the
@Lock
annotation can be used on query
methods:
This method declaration will cause the query being triggered to be
equipped with the
LockModeType
READ
. You can also define locking for CRUD methods by
redeclaring them in your repository interface and adding the
@Lock
annotation:
Example 2.22. Defining lock metadata on CRUD methods
interface UserRepository extends Repository<User, Long> { // Redeclaration of a CRUD method @Lock(LockModeType.READ); List<User> findAll(); }
Here's an example implementation of the interface using Spring
Security's
Authentication
object:
The implementation is accessing the
Authentication
object provided by Spring
Security and looks up the custom
UserDetails
instance from it that you have
created in your
UserDetailsService
implementation. We're assuming here that you are exposing the domain user
through that
UserDetails
implementation but
you could also look it up from anywhere based on the
Authentication
found.
Note that the auditing feature requires
spring-aspects.jar
to be on the classpath.
Now activating auditing functionality is just a matter of adding
the Spring Data JPA
auditing
namespace element to
your configuration:
Example 2.26. Activating auditing using XML configuration
<jpa:auditing auditor-aware-ref="yourAuditorAwareBean" />
As of Spring Data JPA 1.5, auditing can be enabled by annotating a
configuration class with the
@EnableJpaAuditing
annotation.
Example 2.27. Activating auditing via Java configuration
@Configuration @EnableJpaAuditing class Config { @Bean public AuditorAware<AuditableUser> auditorProvider() { return new AuditorAwareImpl(); }
If you expose a bean of type
AuditorAware
to the
ApplicationContext
, the auditing
infrastructure will pick it up automatically and use it to determine the
current user to be set on domain types. If you have multiple
implementations registered in the
ApplicationContext
, you can select the
one to be used by explicitly setting the
auditorAwareRef
attribute of
@EnableJpaAuditing
.
![]() |
Note |
---|---|
As of Spring 3.1 a package to scan can be configured on the
|
Instances of the repository interfaces are usually created by a container, which Spring is the most natural choice when working with Spring Data. There's sophisticated support to easily set up Spring to create bean instances documented in Section 1.2.3, “Creating repository instances” . As of version 1.1.0 Spring Data JPA ships with a custom CDI extension that allows using the repository abstraction in CDI environments. The extension is part of the JAR so all you need to do to activate it is dropping the Spring Data JPA JAR into your classpath.
You can now set up the infrastructure by implementing a CDI
Producer
for the
EntityManagerFactory
and
EntityManager
:
class EntityManagerFactoryProducer { @Produces @ApplicationScoped public EntityManagerFactory createEntityManagerFactory() { return Persistence.createEntityManagerFactory("my-presistence-unit"); public void close(@Disposes EntityManagerFactory entityManagerFactory) { entityManagerFactory.close(); @Produces @RequestScoped public EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) { return entityManagerFactory.createEntityManager(); public void close(@Disposes EntityManager entityManager) { entityManager.close(); }
The necessary setup can vary depending on the JavaEE environment
you run in. It might also just be enough to redeclare a
EntityManager
as CDI bean as
follows:
class CdiConfig { @Produces @RequestScoped @PersistenceContext public EntityManager entityManager; }
In this example, the container has to be capable of creating JPA
EntityManager
s itself. All the
configuration does is re-exporting the JPA
EntityManager
as CDI bean.
The Spring Data JPA CDI extension will pick up all
EntityManager
s availables as CDI beans
and create a proxy for a Spring Data repository whenever an bean of a
repository type is requested by the container. Thus obtaining an
instance of a Spring Data repository is a matter of declaring an
@Inject
ed property:
class RepositoryClient { @Inject PersonRepository repository;
![]() |
捣蛋的手术刀 · wellerman由来_百度知道 3 月前 |