SpringData Advanced Chapter - Part 2

One: Story Background

This is my third SpringData article. In the previous article, we described how to configure projects through XML and JavaConfig, and use SpringData to perform CRUD without using Sql statements. In this article, we will continue to describe SpringData from two parts. On the one hand, it is to meet the custom operations of our complex business. The purpose of this article is to let everyone improve the usability of SpringData and use it to support complex businesses.

Two: Custom operation

2.1 JPQL and SQL

JPQL is a query language based on the object model, which is used to perform database operations in the Java persistence framework. Here we directly give corresponding examples to show how to use JPQL for data operations.

2.1.1 Definition in interface

JPQL mainly implements query through @Query annotation, which is written as follows:

	@Query("from User where userName=?1")
    List<User> findUserByName(String userName);
    
    @Query("from User where userName=:userName")
    List<User> findUserByName2(@Param("userName") String userName);

Two methods of specifying parameters are given above, the first one is through? The way of adding index, the second way is to specify the parameter name through @Param.
If it is an addition, deletion, or modification operation, you need to add @Modifying to the query method of life, tell jpa this modification statement, and add @Transactional annotation to the business layer to ensure the transactional nature of the operation

 @Query("update User u set u.userName=:userName where u.id=:id")
    @Modifying
    int updateUserById(@Param("id") Long id,@Param("userName") String userName);

2.1.2 Call

	@Test
    public void test(){
    
    
        List<User> name = iUserRepository2.findUserByName("郝立琢");
        for (User user : name) {
    
    
            System.out.println(user.getUserName());
        }
    }

    @Test
    @Transactional
    public void testU(){
    
    
        int i = iUserRepository2.updateUserById(1L,"郝666");
        System.out.println("更新成功了~~~"+i);
    }

Here is an IDEA plug-in JPA Buddy , which can give us hints and make our coding easier

2.2.3 SQL query

Through the nativeQuery attribute of @Query, we can specify the use of SQL queries. When using SQL queries, we must pay attention to the correctness of SQL. Don't write and get used to JPQL and directly use JPQL for corresponding writing.

@Query(value = "select * from user",nativeQuery = true)
    List<User> selectAll();

2.2 Specify method name

It is a simpler way to specify the method name. We only need to set the corresponding method in the interface according to the corresponding rules, and then we can use it directly

2.2.1 Common query rules

insert image description here

2.2.2 Modified query

insert image description here
insert image description here
insert image description here
This method eliminates the need to write JPQL yourself, which is simpler in comparison.

2.3 Query By Example

Query by Example translated into Chinese means example query, which allows dynamic creation of queries, and does not require writing queries containing field names, and supports flexible matching of string types and other types of exact matching. However, nested or grouped attribute constraints are not supported.
The following are specific examples:

2.3.1 Repository inherits QueryByExampleExecutor

Inherit Repository from QueryByExampleExecutor to use example query by inheriting this interface

public interface IUserRepository3 extends PagingAndSortingRepository<User,Long>,QueryByExampleExecutor<User> {
    
    
}

2.3.2 Specific use

The process of specific use mainly involves two parts. The first part is the Example class, which is used to declare specific examples, and set specific matching conditions through ExampleMatcher.

@ContextConfiguration(classes = SpringDataJpaConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringDataTest4 {
    
    

    private static final Logger logger = Logger.getLogger(SpringDataTest4.class.getName());

    @Autowired
    private IUserRepository3 iUserRepository3;

    @Test
    public void test() {
    
    
        User user = new User();
        user.setId(1l);
        user.setUserName("郝立琢");

        //这里注意使用的是org.springframework.data.domain.Example而不是hibernate的Example
        Example<User> example = Example.of(user);
        List<User> list = (List<User>) iUserRepository3.findAll(example);
        logger.info(String.valueOf(list));

    }

    @Test
    public void test2() {
    
    
        User user = new User();
        user.setUserName("haolizhuo");

        //匹配器,设置多条件匹配
       ExampleMatcher matcher = ExampleMatcher.matching().
               //忽略id
               withIgnorePaths("id").
               //忽略大小写
               withIgnoreCase("userName");

        //这里注意使用的是org.springframework.data.domain.Example而不是hibernate的Example
        Example<User> example = Example.of(user,matcher);
        List<User> list = (List<User>) iUserRepository3.findAll(example);
        logger.info(String.valueOf(list));

    }

}

2.3.2 Commonly used methods and their functions in the ExampleMatcher class

insert image description here

2.4 Specifications

Before using Query by Example, you can only set conditions for strings. If you want to support all types, you can use Specifications. The basic writing method is given below.

 @Test
    public void test() {
    
    

        //使用内部类的方式直接进行查询
        List<User> all = iUserRepository4.findAll((Specification<User>) (root, query, criteriaBuilder) -> {
    
    

            // root 可以用来获取某个列
            // query where 设置各种条件
            // criteriaBuilder 组合(order by ,where)

            Path<String> id = root.get("id");
            Path<String> userName = root.get("userName");

            //参数一,为那个字段设置条件、参数2 为条件设置的值
            Predicate equal = criteriaBuilder.equal(userName, "郝立琢");

            return equal;
        });

        logger.info(all.get(0).getUserName());

    }

This method is mainly through the Specification interface, which has three important parameters. The first is root used to obtain a certain column, query to set various conditions, and criteriaBuilder combination to query. We can define personalized queries through Specification, but it is very complicated to use.

Three: Multi-table association

3.1 One-on-one

Define a one-to-one relationship, and you can associate two tables. Through configuration, whether it is addition, deletion, modification, query, it can be directly used through the corresponding data object. Its implementation is mainly realized through the @OneToOne annotation and some of its attributes.

  1. cascade attribute:
    ALL: all
    PERSIST: insert
    MERGE: modify
    REMOVE: delete
  2. fetch attribute:
    EAGER: the default is EAGER to load
    LAZY immediately. Lazy loading is used to query.
    Lazy loading must configure transactions. Otherwise, the Session object will be released after querying, and it will not be loaded when used below.
  3. orphanRemoval attribute:
    Association removal (usually used when modifying), once the associated data is set to null, the associated data will be deleted
  4. optional attribute:
    the default is true, if it is set to false, the associated object is limited to null
  5. mappedBy attribute:
    maintain the foreign key constraint on the other side, it needs to be configured when one-to-one
    bidirectional

3.1.1 One-to-one

One-way one-to-one means that one table is associated with another table. For example, we have a chapter of Customer table and a chapter of Account table, and set a foreign key in Customer to store the ID of Account. Indicates a one-way one-to-one association with the Account table in the Customer table.

@Data
@Entity
@Table(name = "customer")
public class Customer {
    
    

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String userName;

    private String phone;

    @OneToOne(cascade = CascadeType.PERSIST,fetch = FetchType.LAZY)
    /**
     指定外键Id
     **/
    @JoinColumn(name = "account_id")
    private Account account;

}

In this example, we specify a one-to-one relationship through the @OneToOne annotation, specify the id of the corresponding Account table through @JoinColumn, and make a one-way association between the two tables. When we query the Customer table, the account data will be automatically checked out

3.1.2 Two-way one-to-one

When bidirectional one-to-one means, on the basis of the one-way one-to-one we mentioned above, a field is also specially set in the Account table to store the primary key of the Customer table, so that the data of the Customer table can also be brought up when querying the data of the Account.
It should be noted here that we can specify a party to perform dependency constraints through the mappedBy attribute of the @OneToOne annotation.

@Data
@Entity
@Table(name = "account")
public class Account {
    
    

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String accountName;

    @OneToOne(mappedBy = "account")
    @JoinColumn(name = "customer_id")
    private Customer customer;

}

3.2 One-to-many

In the one-to-many way, we need to maintain a List type object of the many side on the one side, and specify the one-to-many relationship through @OneToMany, and specify a maintained id through the @JoinColumn annotation, and this id will be stored in the table of the many side, representing the one-to-many relationship. A one-to-many relationship is suitable for query use.

    /**
     一对多的信息,默认就是懒加载。与一对一相反
     **/
    @OneToMany
    @JoinColumn(name="message_id")
    private List<Message> messageList;

For example, we create a new Customer class and a Message class. The Customer class and the Message class have a one-to-many relationship. We can declare a List collection in the Customer class to represent the one-to-many relationship.
It should be noted here that the one-to-many relationship defaults to lazy loading , which is the opposite of one-to-one, because the data associated with a one-to-many relationship is often more, and the lazy loading method (note that the query uses transaction annotations) can greatly improve efficiency.

3.3 Many-to-one

In the many-to-one way, we need to declare an object on the many side and one side. Using the above example, it refers to declaring an object of type Customer in the Message class.

    /**
     多对一的关系,适合存储多条信息的时候
     **/
    @ManyToOne
    private Customer customer;

Since our above example has maintained @JoinColumn(name="message_id") in one-to-many, it is not necessary to specify repeatedly here.
The many-to-one relationship is more suitable for storing the information of more than one party. By assigning values ​​to customers, the corresponding information is associated.

3.4 Many-to-many

The many-to-many relationship will generate a corresponding intermediate table, and the many-to-many relationship is maintained through the intermediate table.


    /**
     多对多的关系将会产生中间表,通过中间表维护多对多关系
     **/
    @ManyToMany
    @JoinTable(
            name = "customer_role",
            joinColumns = {
    
    @JoinColumn(name = "c_id")},
            inverseJoinColumns = {
    
    @JoinColumn(name = "r_id")}
    )
    private List<Role> roles;

Four: Summary & Improvement

In this article, we describe the various query methods of SpringData, how to associate between multiple tables, and the data operation after association. Through this article, I believe you have learned how to use SpringData for development.
Our following articles will analyze the underlying principles and the integration methods in specific projects. If you are interested, you can continue to pay attention to my column~

Guess you like

Origin blog.csdn.net/hlzdbk/article/details/131052759