Spring Data Jpa (2): use and source code analysis of Spring Data Jpa
- 1, Overview of Spring Data JPA
- 2, Getting started
- 2.1 integrating Spring Data JPA and Spring
- 2.2 use JPA annotation to configure mapping relationship
- 2.3 use Spring Data JPA to complete requirements
- 3, Source code analysis of Spring Data JPA
- 3.1 common interface analysis of Spring Data JPA
- 3.2 implementation process of Spring Data JPA
- 3.3 complete call process analysis of Spring Data JPA
- 4, Query method of Spring Data JPA
1, Overview of Spring Data JPA
1.1 Spring Data JPA
Spring Data JPA is a set of spring encapsulation based on ORM and JPA specification, which enables developers to access and operate the database with simple code. It provides common functions including addition, deletion, modification and query, and is easy to expand! Learning and using Spring Data JPA can greatly improve development efficiency!
Spring Data JPA frees us from the operation of DAO layer, basically all CRUD can be realized by relying on it. In the actual work project, it is recommended to use Spring Data JPA + ORM (such as hibernate) to complete the operation, which provides great convenience when switching different ORM frameworks, and also makes the operation of database layer simpler and easier to decouple.
SpringData Jpa greatly simplifies the database access layer code. How to simplify it? With spring datajpa, we only need to write the interface in the dao layer, which automatically has the methods of adding, deleting, modifying and querying, paging and so on.
1.2 relationship between Spring Data JPA, JPA and hibernate
JPA is a set of specifications, which is composed of interfaces and abstract classes. Hibernate is a mature ORM framework, and Hibernate implements the JPA specification, so we can also call hibernate an implementation of JPA. We use the API programming of JPA, which means we look at the problem from a higher perspective (interface oriented programming)
Spring Data JPA is a set of more advanced encapsulation of JPA operations provided by spring. It is a solution specially used for data persistence under the JPA specification. (with another layer of packaging)
2, Getting started
Spring Data JPA completes basic CRUD operations of customers
To use Spring Data JPA, you need to integrate spring and Spring Data JPA, and provide hibernate, the service provider of JPA, so you need to import spring related coordinates, hibernate coordinates, database driven coordinates, etc
<properties> <spring.version>4.2.4.RELEASE</spring.version> <hibernate.version>5.0.7.Final</hibernate.version> <slf4j.version>1.6.6</slf4j.version> <log4j.version>1.2.12</log4j.version> <c3p0.version>0.9.1.2</c3p0.version> <mysql.version>5.1.6</mysql.version> </properties> <dependencies> <!-- junit unit testing --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency> <!-- spring beg --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.8</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <!-- spring end --> <!-- hibernate beg --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.2.1.Final</version> </dependency> <!-- hibernate end --> <!-- c3p0 beg --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>${c3p0.version}</version> </dependency> <!-- c3p0 end --> <!-- log end --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <!-- log end --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.9.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.2.4.RELEASE</version> </dependency> <!-- el beg Use spring data jpa Must introduce --> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>2.2.4</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>javax.el</artifactId> <version>2.2.4</version> </dependency> <!-- el end --> </dependencies>
2.1 integrating Spring Data JPA and Spring
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <!-- 1.dataSource Configure database connection pool--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/jpa" /> <property name="user" value="root" /> <property name="password" value="111111" /> </bean> <!-- 2.To configure entityManagerFactory --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan" value="cn.itcast.entity" /> <property name="persistenceProvider"> <bean class="org.hibernate.jpa.HibernatePersistenceProvider" /> </property> <!--JPA Vendor adapter for--> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="generateDdl" value="false" /> <property name="database" value="MYSQL" /> <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" /> <property name="showSql" value="true" /> </bean> </property> <property name="jpaDialect"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" /> </property> </bean> <!-- 3.Transaction manager--> <!-- JPA Transaction manager --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <!-- integration spring data jpa--> <jpa:repositories base-package="cn.itcast.dao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories> <!-- 4.txAdvice--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="insert*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="get*" read-only="true"/> <tx:method name="find*" read-only="true"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!-- 5.aop Declarative transaction--> <aop:config> <aop:pointcut id="pointcut" expression="execution(* cn.itcast.service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" /> </aop:config> <context:component-scan base-package="cn.itcast"></context:component-scan> <!--Assemble other configuration files--> </beans>
2.2 use JPA annotation to configure mapping relationship
The Customer entity class object in our use case has been configured with mapping relationship
package cn.itcast.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; /** * * * All annotations are provided by JPA specifications, * * So when importing annotation packages, you must import the */ @Entity //Declaration entity class @Table(name="cst_customer") //Establish the mapping relationship between entity class and table @Data public class Customer { @Id//Declare the current private property as the primary key @GeneratedValue(strategy=GenerationType.IDENTITY) //Configure primary key generation policy @Column(name="cust_id") //Specify the mapping relationship with cust? ID field in the table private Long custId; @Column(name="cust_name") //Specify the mapping relationship with cust'name field in the table private String custName; @Column(name="cust_source")//Specify the mapping relationship with cust source field in the table private String custSource; @Column(name="cust_industry")//Specify the mapping relationship with cust "industry field in the table private String custIndustry; @Column(name="cust_level")//Specify the mapping relationship with cust "level field in the table private String custLevel; @Column(name="cust_address")//Specify the mapping relationship with cust "address field in the table private String custAddress; @Column(name="cust_phone")//Specify the mapping relationship with cust? Phone field in the table private String custPhone; }
2.3 use Spring Data JPA to complete requirements
2.3.1 write Dao layer interface conforming to Spring Data JPA specification
Spring Data JPA is a framework of data access layer (Dao layer) provided by spring. It can complete the definition of database addition, deletion, modification and query, paging query and other methods without implementation classes, greatly simplifying our development process.
In Spring Data JPA, we only need to follow the following points to define the Dao layer interface that meets the specification:
1. Create a Dao layer interface and implement JpaRepository and jpaspecification executor 2. Provide corresponding generics
package cn.itcast.dao; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import cn.itcast.entity.Customer; /** * JpaRepository<Entity class type, primary key type >: used to complete basic CRUD operations * JpaSpecificationExecutor<Entity class type >: used for complex query (paging and other query operations) */ public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> { }
In this way, we have defined a Dao layer interface that conforms to the Spring Data JPA specification
2.3.2 complete basic CRUD operation
After setting up the environment of Spring Data JPA and writing the Dao layer interface in line with the Spring Data JPA specification, you can use the defined Dao layer interface to perform basic CRUD operations for customers
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class CustomerDaoTest { @Autowired private CustomerDao customerDao; /** * Save customer: call save(obj) method */ @Test public void testSave() { Customer c = new Customer(); c.setCustName("xxx"); customerDao.save(c); } /** * Modify customer: call save(obj) method * Explanation for the save method: if the method is executed because there is an id attribute in the object, the update operation will first query and update according to the id * * If the id attribute does not exist in the object in this method, it is a save operation * */ @Test public void testUpdate() { //Query the customer with id 1 according to id Customer customer = customerDao.findOne(1l); //Modify customer name customer.setCustName("Zhichuan podcast Shunyi Campus"); //To update customerDao.save(customer); } /** * Delete according to id: call delete(id) method */ @Test public void testDelete() { customerDao.delete(1l); } /** * Query according to id: call findOne(id) method */ @Test public void testFindById() { Customer customer = customerDao.findOne(2l); System.out.println(customer); } }
3, Source code analysis of Spring Data JPA
3.1 common interface analysis of Spring Data JPA
In the custom CustomerDao, many of these methods can be used without providing any methods, so how do these methods come from?
The answer is simple. For our custom Dao interface, we can use all the methods of the two interfaces because we inherit the JpaRepository and jpasecification executor. But these methods are just declarations, and there is no specific way to implement them. So how is it implemented in Spring Data JPA?
3.2 implementation process of Spring Data JPA
By analyzing the original Spring Data JPA to analyze the execution process of the program, we take findOne method as an example.
- Implementation process of agent subclass
When the breakpoint is executed on the method, we can find that the injected customerDao object is essentially a proxy object generated by JdkDynamicAopProxy.
- Analysis of method call in proxy object
When the program is executed, the dynamic proxy object is generated for the customerDao object through the invoke method of JdkDynamicAopProxy. If you want to perform findOne query method, the API of JPA specification will finally appear to complete the operation, where are these underlying codes? The answer is very simple. It is hidden in the dynamic proxy object generated by JdkDynamicAopProxy, which is simplejparpository.
Through the source code analysis of simplejpaepository, the findOne method is located. In this method, the return result of em.find() is returned. We find that EM is the EntityManager object, which is the native implementation of JPA.
Conclusion: Spring Data JPA only further encapsulates the standard JPA operations, simplifying the development of Dao layer code
3.3 complete call process analysis of Spring Data JPA
4, Query method of Spring Data JPA
4.1 query using the method defined by the interface in Spring Data JPA
After inheriting the JpaRepository and JpaRepository interfaces, we can use the methods defined in the interfaces to query
- List of methods inherited from JpaRepository
- List of methods (complex queries) that inherit the jpaspecification executor
4.2 Query by @ Query annotation JPQL
Using the Query method provided by Spring Data JPA can solve most of the application scenarios, but for some businesses, we need to flexibly construct the Query conditions. At this time, we can use @ Query annotation and JPQL statement to complete the Query.
Just annotate @ Query on the method and provide a JPQL Query statement.
public interface CustomerDao extends JpaRepository<Customer, Long>,JpaSpecificationExecutor<Customer> { //@Query queries using jpql. @Query(value="from Customer") public List<Customer> findAllCustomer(); //@Query queries using jpql. ? 1 represents a placeholder for the parameter, where 1 corresponds to the parameter index in the method @Query(value="from Customer where custName = ?1") public Customer findCustomer(String custName); }
In addition, you can also use @ Query to perform an update operation. To do this, we need to use @ Query and @ Modifying to mark the operation as Modifying Query, so that the framework will eventually generate an update operation instead of a Query
@Query(value="update Customer set custName = ?1 where custId = ?2") @Modifying//It shows that the method is modified public void updateCustomer(String custName,Long custId);
4.3 query with SQL statement
@Query also supports query of sql statements, as follows:
/** * nativeQuery : Query using local sql */ @Query(value="select * from cst_customer",nativeQuery=true) public void findSql();
4.4 method naming rule query
As the name implies, method naming rule query is to create a query based on the name of the method. You can complete the query by defining the name of the method according to the method naming rules provided by Spring Data JPA.
The query method starts with findBy. When it comes to condition query, the attributes of the condition are connected with the condition keyword. Note that the initial of the condition attribute should be capitalized. When the framework resolves method names, it will first truncate the redundant prefixes of method names, and then parse the rest.
//Method name method query (query customer by customer name) public Customer findByCustName(String custName);
Specific keywords, usage and production into SQL are shown in the following table