Spring data simplifies JPA development_ Power node Java college sorting

Start with a simple JPA example

This article focuses on spring data JPA, but in order not to cause a large learning curve for beginners of JPA and spring, let's start with JPA and briefly introduce a JPA example; Then refactor the example and introduce the spring framework. These two parts will not involve too much space. If you want to learn more about spring and JPA, you can learn further according to the resources provided at the end of this article.

Since the release of JPA with Java EE 5, it has been sought after by major manufacturers and open source communities. Various commercial and open source JPA frameworks have sprung up, providing developers with rich choices. It changes the previous EJB 2 The image of entity bean in X is cumbersome and difficult to use, which fully absorbs the ORM idea that has been relatively mature in the open source community. In addition, it does not depend on EJB container and can exist as an independent persistence layer technology. At present, more mature JPA frameworks mainly include hibernate entitymanager of JBoss, eclipse link donated by Oracle to eclipse community, openjpa of Apache, etc.

The sample code of this article is developed based on Hibernate entitymanager, but the reader can easily switch to other JPA frameworks without modifying any code, because the code uses the interfaces / classes provided by JPA specification and does not use the private features of the framework itself. The example mainly involves seven files, but it is clear: the business layer includes an interface and an implementation; The persistence layer includes an interface, an implementation and an entity class; Add a JPA configuration file and a test class. Relevant class / interface codes are as follows:

Listing 1 Entity class accountinfo java

Listing 2 Business layer interface userservice java

Listing 3 The implementation class of the business layer is userserviceimpl java

Listing 4 Persistence layer interface

Listing 5 Implementation class of persistence layer

Listing 6 JPA standard configuration file persistence xml

Listing 7 This paper uses the following main method for developer testing

Briefly describe the spring framework's support for JPA

Next, we introduce spring to demonstrate the spring framework's support for JPA. The business layer interface userservice remains unchanged. Three annotations are added in userserviceimpl to allow spring to complete dependency injection. Therefore, it is no longer necessary to use the new operator to create userdaoimpl objects. At the same time, we also use spring's declarative transaction:

Listing 8 Configured as the business layer implementation of spring bean

For the persistence layer, the userdao interface does not need to be modified, just the userdaoimpl implementation. The modified code is as follows:

Listing 9 Configured as the persistence layer implementation of spring bean

Listing 10 Spring configuration file

Listing 11 Modified spring based developer test code

By comparing the code before and after refactoring, we can find that spring's simplification of JPA has been excellent. We can roughly summarize the spring framework's support for JPA, which is mainly reflected in the following aspects:

First, it makes JPA configuration more flexible. The JPA specification requires that the configuration file must be named persistence XML and exists in the meta-inf directory under the classpath. This file usually contains all the information needed to initialize the JPA engine. The localcontainerentitymanagerfactorybean provided by spring provides very flexible configuration and persistence The information in XML can be provided here in the form of attribute injection.

Secondly, spring implements some functions only in the EJB container environment, such as container injection support for @ persistencecontext and @ persistenceunit.

Third, and most significant, spring extracts and manages the codes such as the creation and destruction of entitymanager and transaction management. Developers do not need to care about these. As shown in the previous code, only the code of operation domain objects is left in the business method, and the code created and destroyed by event management and entitymanager no longer needs developers to care about.

Further: Spring data JPA makes everything almost perfect

From the previous analysis, we can see that spring has strong support for JPA. Developers only need to care about the implementation code of core business logic, and do not need to pay too much attention to JPA related processing such as the creation of entitymanager and transaction processing. This is basically the limit that can be achieved as a development framework. However, the spring development team has not stopped. They have made persistent efforts and recently launched the spring data JPA framework, which is mainly aimed at the only business logic code that spring has not simplified. So far, the developers have saved the only work left to implement the business logic of the persistence layer, and the only thing to do is to declare the interface of the persistence layer, Let spring data JPA do the rest for you!

At this point, readers may have a question, how can a framework replace developers to implement business logic? After all, the persistence layer business and even domain objects of each application are different. How does the framework do it? In fact, the idea behind this is not complicated. For example, when you see userdao A method declaration like finduserbyid () should roughly determine that this is to query the user object satisfying the condition according to the ID of the given condition. What spring data JPA does is to standardize the name of the method, and determine what logic the method needs to implement according to the name conforming to the specification.

Next, we will transform the previous example and let spring data JPA help us complete the business logic. Before writing the code, developers need to download the release package of spring data JPA (spring data Commons and spring data JPA need to be downloaded at the same time. Commons is the common basic package of spring data), and add the relevant dependent jar files to the classpath.

First, let the persistence layer interface userdao inherit the repository interface. The interface uses generics and needs to provide two types: the first is the domain object type processed by the interface, and the second is the primary key type of the domain object. The modified userdao is as follows:

Listing 12 Spring data JPA style persistence layer interface

Then delete the userdaoimpl class, because as we said earlier, the framework will complete the business logic for us. Finally, we need to add the following configuration in the spring configuration file to enable spring to identify the persistence layer interface that needs to be implemented for it:

Listing 13 Enable the ability to scan and automatically create proxies in the spring configuration file

So far, it's done! Execute the test code, and then look at the database. The new data has been added to the table as expected. What should I do if I want to add a new persistence layer business, such as the accountinfo object with ID? Simply add a line of code to the userdao interface:

Listing 14 Add a method declaration to the modified persistence layer interface

The following is a summary of the three steps required to develop the persistence layer using spring data JPA:

1. Declare the interface of the persistence layer, which inherits repository. Repository is a marked interface, which does not contain any methods. Of course, if necessary, spring data also provides several repository sub interfaces, which define some common addition, deletion, modification and query, as well as paging related methods.

2. Declare the required business methods in the interface. Spring data will generate implementation code for a given strategy (the specific strategy will be explained later).

3. Add a line of declaration in the spring configuration file to let spring create a proxy object for the declared interface. After < JPA: repositories > is configured, when spring initializes the container, it will scan the package directory and its subdirectories specified by the base package, create a proxy object for the interface that inherits the repository or its sub interface, and register the proxy object as a spring bean. The business layer can directly use the object through the features automatically encapsulated by spring.

In addition, < JPA: repository > also provides some attributes and sub tags to facilitate finer grained control. You can use < context: include Filter >, < context: Exclude Filter > inside < JPA: repository > to filter out some interfaces that you don't want to be scanned.

Which interface should I inherit?

As mentioned earlier, inheriting repository from the persistence layer interface is not the only option. The repository interface is a core interface of spring data. It does not provide any methods. Developers need to declare the required methods in their own defined interfaces. One way equivalent to inheriting repository is to use the @ repositorydefinition annotation on the persistence layer interface and specify domainclass and IdClass attributes for it. The following two methods are completely equivalent:

Listing 15 Examples of two equivalent inheritance interface modes

If there are many persistence layer interfaces, and each interface needs to declare similar addition, deletion, modification and query methods, it is a bit cumbersome to directly inherit the repository. It will automatically create addition, deletion, modification and query methods for domain objects for direct use by the business layer. Developers just wrote four more letters of "crud", and immediately provided ten methods for adding, deleting, modifying and querying domain objects out of the box.

However, using crudrepository also has side effects, which may expose methods you don't want to expose to the business layer. For example, for some interfaces, you only want to provide adding operations rather than deleting methods. In this case, developers can only return to the repository interface, and then copy the method declaration they want to keep to the custom interface in crudrepository.

Paging query and sorting are common functions of the persistence layer. Spring data provides a pagingandsortingreposition interface for this purpose. It inherits from the crudrepository interface and adds two paging related methods on the basis of crudrepository. However, we rarely inherit the custom persistence layer interface directly from pagingandsortingrepository. Instead, on the basis of inheriting repository or crudrepository, we can add a pageable or sort type parameter at the end of the method parameter list declared by ourselves to specify paging or sorting information, This provides greater flexibility than using pagingandsorting repository directly.

Jparepository is an interface for JPA technology inherited from pagingandsortingreposition. Based on the parent interface, it provides other methods, such as flush(), saveandflush(), deleteinbatch(). If there is such a requirement, you can inherit the interface.

How should developers choose the above four interfaces? In fact, the basis is very simple. Select one of them according to specific business needs. The author suggests that in general, the repository interface should be preferred. Because the repository interface can meet daily needs, what other interfaces can do can also be done in the repository. There is no problem of function strength between them. Only the repository needs to display the methods required by the declaration, while others may have provided relevant methods and do not need to be explicitly declared. However, if they are unfamiliar with spring data JPA, others will have doubts when viewing the code or taking over the relevant code. They do not understand why three methods are clearly declared in the persistence layer interface, and when the business layer uses the interface, However, seven or eight methods are found to be available. From this point of view, priority should be given to using the repository interface.

As mentioned earlier, when spring data JPA creates a proxy object for the persistence layer interface in the background, it will resolve the method name and implement the corresponding functions. In addition to the method name, it can also specify query statements in the following two ways:

1. Spring data JPA can access JPA named query statements. Developers only need to specify a name that conforms to the given format when defining the named query statement, and spring data JPA will use the named query statement to realize its functions when creating the proxy object.

2. Developers can also directly use the @ query annotation on the declared method and provide a query statement as a parameter. Spring data JPA will use the provided query statement to realize its function when creating a proxy object.

Next, we describe three ways to create a query.

Create a query by resolving the method name

Through the previous examples, readers basically have a general understanding of how to parse method names and create queries, which is also a very important factor for spring data JPA to attract developers. In fact, this function is not initiated by spring data JPA, but comes from an open source JPA framework Hades. Oliver Gierke, the author of the framework, is also the leader of the spring data JPA project. Therefore, it is natural to introduce the advantages of Hades into spring data JPA.

When parsing the method name, the framework will first intercept the redundant prefix of the method name, such as find, findby, read, readby, get and getby, and then parse the rest. And if the last parameter of the method is of type sort or pageable, relevant information will also be extracted for sorting or paging query according to rules.

When creating a query, we express it by using the attribute name in the method name, such as findbyuseraddresszip(). When the framework parses this method, it first eliminates findby, and then parses the remaining attributes. The detailed rules are as follows (here, it is assumed that the domain object targeted by this method is of accountinfo type):

First judge whether useraddresszip (the initial letter changes to lowercase according to the POJO specification, the same below) is an attribute of accountinfo. If yes, it means to query according to this attribute; if there is no such attribute, continue to step 2;

Intercept the string beginning with the first uppercase letter from right to left (zip here), and then check whether the remaining string is an attribute of accountinfo. If yes, it means to query according to the attribute; if there is no attribute, repeat step 2 and continue to intercept from right to left. Finally, assume that user is an attribute of accountinfo;

Then process the remaining part (addresszip). First judge whether the type corresponding to user has addresszip attribute. If so, it means that the method is finally queried according to the value of "accountinfo. User. Addresszip"; otherwise, continue to cut from right to left according to the rules in step 2, and finally it means that the method is queried according to the value of "accountinfo. User. Address. Zip".

There may be a special case. For example, accountinfo contains a user attribute and a useraddress attribute. There will be confusion at this time. Readers can explicitly add "" between attributes Express the intention explicitly, such as "findbyuser_addresszip()" or "findbyuseraddress_zip()". When querying, you usually need to query according to multiple attributes at the same time, and the query conditions are in various formats (greater than a certain value, in a certain range, etc.). Spring data JPA provides some keywords to express conditional query, which are roughly as follows:

Create a query using @ query

@The use of query annotation is very simple. You only need to mark the annotation on the declared method and provide a JP QL query statement, as shown below:

Listing 16 Use @ query to provide examples of custom query statements

Many developers prefer to use named parameters instead of location numbers when creating jpql, @ query also supports this. In the JP QL statement, the parameters are specified in the format of ": variable". At the same time, use @ param in front of the method parameters to correspond the method parameters to the named parameters in JP QL. An example is as follows:

Listing 17@ Query supports named parameter examples

In addition, developers can also use @ query to perform an update operation. Therefore, we need to use @ modifying to identify the operation as a modify query while using @ query, so that the framework will eventually generate an update operation instead of a query. As follows:

Listing 18 Use @ modifying to identify a query as a modified query

Create a query by calling a JPA named query statement

Named query is a function provided by JPA to separate query statements from method body for common use by multiple methods. Spring data JPA also provides good support for named queries. Users only need to follow the JPA specification in orm XML file or use @ namedquery (or @ namednatequery) to define a query statement in the code. The only thing to do is to meet the naming rules of "domainclass. Methodname()" when naming the statement. It is assumed that the following interfaces are defined:

Listing 19 When using JPA to name queries, no special processing is required when declaring interfaces and methods

If we want to create a named query for findtop5() and associate it with it, we only need to define a named query statement in an appropriate position and name it "accountinfo. Findtop5". When the framework resolves to this method during the creation of the proxy class, it will first find the named query definition named "accountinfo. Findtop5". If it is not found, it will try to resolve the method name, Create a query based on the method name.

The order in which queries are created

When spring data JPA creates proxy objects for interfaces, if it finds that multiple of the above situations are available at the same time, which strategy should it take first? For this purpose, < JPA: repositories > provides the query lookup strategy attribute to specify the search order. It has the following three values:

Spring data JPA support for transactions

By default, the methods implemented by spring data JPA use transactions. The method for query type is equivalent to @ transactional (readonly = true); The method of adding, deleting and modifying types is equivalent to @ transactional. It can be seen that except that the query method is set to read-only transaction, other transaction attributes adopt default values.

If necessary, the user can explicitly specify the transaction attribute on the interface method using @ transactional, which overrides the default value provided by spring data JPA. At the same time, developers can also use @ transactional to specify transaction attributes on business layer methods, which is mainly for the case that a business layer method calls persistence layer methods multiple times. The transaction of the persistence layer will decide whether to suspend the transaction of the business layer or join the transaction of the business layer according to the set transaction propagation behavior.

Provides a custom implementation for some methods in the interface

Sometimes, developers may need to do some special processing in some methods. At this time, the automatically generated proxy object can not fully meet the requirements. In order to enjoy the convenience brought by spring data JPA and provide custom implementation for some methods, we can adopt the following methods:

Bill 20 Specify a custom implementation class

In addition, < JPA: repositories > provides a repository impl postfix attribute to specify the suffix of the implementation class. The following configuration is assumed:

Listing 21 Set the default custom implementation class naming rules for automatic lookup

When the framework scans the accountdao interface, it will try to find accountdaoimpl. In the same package directory Java, if found, the implementation method will be used as the implementation of the corresponding method in the finally generated proxy class.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>