Chapter 02 Spring Data JPA

Section 01- Overview of Spring Data JPA

Spring Data JPA is a set of JPA application framework encapsulated by Spring based on ORM framework and JPA specification, which enables developers to access and operate databases with minimal code. It provides common functions including add, delete, change, check, etc., and easy to expand! Learning and using Spring Data JPA can greatly improve your development efficiency!

Spring Data JPA takes the DAO layer out of the way and basically all CRUDS can rely on it for implementation. In actual working projects, it is recommended to use Spring Data JPA + ORM (e.g. Hibernate), which provides great convenience when switching between DIFFERENT ORM frameworks, and also makes database layer operations simpler and easier to decouple

Spring Data JPA and the relationship between JPA and Hibernate

JPA is a set of specifications made up of interfaces and abstract classes. Hibernate is a mature ORM framework, and Hibernate implements THE JPA specification, so hibernate can also be called as an implementation of JPA. We use JPA API programming, which means that we look at the problem from a higher perspective (interface oriented programming).

Spring Data JPA is a more advanced encapsulation of JPA operations provided by Spring. It is a dedicated solution for Data persistence under the JPA specification.

Section 02-Spring Data JPA Best Practices

  1. Create a Maven project and add project dependencies
<properties>
    <spring.version>5.2.6. RELEASE</spring.version>
    <hibernate.version>5.0.7. The 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>8.0.19</mysql.version>
</properties>

<dependencies>
    <! -- Junit Unit Test -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</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>

    <! Spring support for the ORM framework
    <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. The 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>

    <! -- Spring data jPA coordinates -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.3.4
        .RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <! -- el beg using Spring data -->
    <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>
Copy the code

2. Create a configuration file and configure applicationContext. XML. All classes are managed by Spring


      
<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">

    <! Spring and Spring Data jPA configuration

    <! -- Configure packet scanning -->
    <context:component-scan base-package="com.citi" ></context:component-scan>

    <! Create an entityManagerFactory object for the Spring container to manage.
    <bean id="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <! -- Configure the scanned package (the package where the entity class is) -->
        <property name="packagesToScan" value="com.citi.entity" />
        <! -- JPA implementation manufacturer -->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
        </property>

        <! -- JPA vendor adapter -->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <! Create a database table automatically
                <property name="generateDdl" value="false" />
                <! -- Specify the database type -->
                <property name="database" value="MYSQL" />
                <! Database dialects: unique syntax supported -->
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
                <! SQL > display SQL
                <property name="showSql" value="true" />
            </bean>
        </property>

        <! -- JPA dialect: Advanced features -->
        <property name="jpaDialect" >
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>

    </bean>

    <! Create database connection pool -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test? useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=Asia/Shanghai" ></property>
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
    </bean>

    <! Spring dataJpa-->
    <jpa:repositories base-package="com.citi.dao" transaction-manager-ref="transactionManager"
                      entity-manager-factory-ref="entityManagerFactoty" ></jpa:repositories>

    <! 4. Configure transaction manager -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactoty"></property>
    </bean>

    <! -- 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-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.citi.service.*.*(..) )" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
    </aop:config>
</beans>
Copy the code

3. Create an entity class Customer in the Entity package and configure the mapping relationship between the entity class and the table, and between attributes and fields

@entity // indicates an Entity class @table (name = "Customer ") // Mapping indicates public class Customer {@id // declare primary key @GeneratedValue(strategy =) Generationtype.identity)// Declare primary key generation policy @column (name = "CUST_ID ") // Private Long custId; @Column(name = "cust_name") private String custName; @Column(name = "cust_source") private String custSource; @Column(name = "cust_level") private String custLevel; @Column(name = "cust_industry") private String custIndustry; @Column(name = "cust_phone") private String custPhone; @Column(name = "cust_address") private String custAddress; // omit the getter/setter/toString method}Copy the code

4. Create the CustomerDao interface class in the DAO layer and inherit JpaRepository and JpaSpecificationExecutor

/** * JpaRepository generic the first is the entity class of the operation, and the second is the primary key type */
public interface CustomerDao extends JpaRepository<Customer.Long>,JpaSpecificationExecutor<Customer> {}Copy the code

5. Create the CustomerDaoTest test class in the test package and create the testFindById method

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class CustomerDaoTest {

    @Autowired
    private CustomerDao customerDao;

    /** * query by ID */
    @Test
    public void testFindById(a){
        Customer customer = customerDao.findOne(2l); System.out.println(customer); }}Copy the code

Save () Saves or updates the operation

@Test
public void testSave(a){
    // Save or update. If data exists, update it. If data does not exist, create it
    Customer customer = new Customer();
    customer.setCustName("Thor");
    customer.setCustSource("Asgard");
    customer.setCustLevel("VIP");
    customer.setCustIndustry("God of Thunder");
    customerDao.save(customer);
}

@Test
public void testUpdate(a){
    // Save or update. If data exists, update it. If data does not exist, create it
    Customer customer = customerDao.findOne(3l);
    customer.setCustSource("INS");
    customerDao.save(customer);
}
Copy the code

Delete () Delete operation

@Test
public void testDelete(a){
    customerDao.delete(3l);
}
Copy the code

FindAll () queries all operations

@Test
public void testFindAll(a){
    List<Customer> customerList = customerDao.findAll();
    for(Customer customer : customerList) { System.out.println(customer); }}Copy the code

Implementation process

I: The instantiated customerDao is a dynamic proxy object SimpleJpaRepository

II:SimpleJpaRepository calls findOne(), and findOne() calls find() through the entity class manager EM to complete the query

Section 03- How to complete complex queries using Spring Data JPA

Query count()

@Test
public void testCount(a){
    long count = customerDao.count();
    System.out.println(count);
}
Copy the code

Does there exist ()

@Test
public void testExists(a){
    boolean isExists = customerDao.exists(1l);
    System.out.println(isExists);
}
Copy the code

Query getOne() by ID

@Test
@Transactional
public void testGetOne(a){
    Customer one = customerDao.getOne(1l);
    System.out.println(one);
}
Copy the code

The underlying call is getReference() of the EntityManager, loaded lazily, while find() is loaded immediately

Query methods in JPA:

Use JPQL for complex queries

JPQL: JPA Query Language

Features: The syntax or keywords are similar to SQL statements. It queries classes and properties within classes

The JPQL statement needs to be configured on the interface method

  • Specific queries that require methods to be configured on the DAO interface
  • Configure JPQL statements with annotations on the newly added methods
  • Annotated as @ Query

New methods in the CustomerDao interface to query customers by customer name, using JPQL statements

@Query(value = "from Customer where custName= ?" )
Customer findByCustName(String custName);
Copy the code

Test the method in the CustomerDao

@Test
public void testFindByCustName(a){
    Customer thor = customerDao.findByCustName("Thor");
    System.out.println(thor);
}
Copy the code

The output

Multi-condition (multi-placeholder) queries

Add methods to the CustomerDao interface

// Query customers based on their names and ids
@Query(value = "from Customer where custName = ? and custId=?" )
Customer findByCustNameAndCustId(String custName, Long custId);
Copy the code

Test the method in CustomerDaoTest

@Test
public void testFindByCustNameAndCustId(a){
    Customer thor = customerDao.findByCustNameAndCustId("Thor".3L);
    System.out.println(thor);
}
Copy the code

Update custName with custId

The updateCustNameByCustId method is added to the CustomerDao interface

// Specify the position of the argument
// Declare an update operation
@Query(value = "update Customer set custName = ? 2 where custId = ? 1)"
@Modifying
@Transactional
void updateCustNameByCustId(Long custId, String custName);
Copy the code

Test the method in CustomerDaoTest

@Test
public void testUpdateCustName(a){
    customerDao.updateCustNameByCustId(3L."Thor Odin");
}
Copy the code

Use SQL statements to complete complex queries

  • Specific queries that require methods to be configured on the DAO interface
  • On the newly added method, SQL query statements are configured in the form of annotations
  • The annotation is @query (value=,nativeQuery=). Value indicates JPQL statement or SQL statement. NativeQuery indicates Boolean

SQL statement query all

Define method selectAll()

@Query(value = "SELECT * FROM customer", nativeQuery = true)
List<Customer> selectAll(a);
Copy the code

Test the method

@Test
public void testSelectAll(a){
    List<Customer> customers = customerDao.selectAll();
    for(Customer customer : customers) { System.out.println(customer); }}Copy the code

The output

SQL statement fuzzy query

Define the method selectByCustNameLike

@Query(value = "SELECT * FROM customer where cust_name like ? 1", nativeQuery = true)
List<Customer> selectByCustNameLike(String like);
Copy the code

Test the method

@Test
public void testSelectByCustNameLike(a){
    List<Customer> customers = customerDao.selectByCustNameLike("Thor%");
    for(Customer customer : customers) { System.out.println(customer); }}Copy the code

The output

Method name rule query

JPQL is a deeper layer of encapsulation for JPQL queries. You only need to define methods according to the method name rules provided by Spring Data JPA, and do not need to configure JPQL statements to complete the query

Naming rules: FindBy is used for the query. The attribute in the object is the query condition. For example, Customer is to be queried through custName. Select * from Customer where CUST_name =? By default, = is used. For fuzzy query, the keyword Like is used

findByCustName

Customer findByCustName(String custName);
Copy the code
@Test
public void testFindByCustName(a){
    Customer thor = customerDao.findByCustName("Thor Odin");
    System.out.println(thor);
}
Copy the code

The output

FindByCustNameLike fuzzy query

List<Customer> findByCustNameLike(String custName);
Copy the code
@Test
public void testFindByCustNameLike(a){
    List<Customer> customers = customerDao.findByCustNameLike("Thor%");
    for(Customer customer : customers) { System.out.println(customer); }}Copy the code

The output

The findByCustNameAndCustId multi-conditional query uses the And keyword, And the order of the attributes of the query should be the same as the order of the input parameters

Customer findByCustNameLikeAndCustIndustry(String custName, String custIndustry);
Copy the code
@Test
public void testFindByCustNameLikeAndCustIndustry(a){
    Customer stark_industry = customerDao.findByCustNameLikeAndCustIndustry("Iron%"."Military Industry");
    System.out.println(stark_industry);
}
Copy the code