What is the difference between Hibernate SpringDataJpa and Mybatis?

 

1. Preface
ps: In the second semester of my junior year, I got an internship. After entering the company, I found that the technology stack used included Spring Data Jpa\Hibernate, but for the persistence layer framework, I only came into contact with Mybatis\Mybatis-Plus, so I came to learn Spring Data Jpa.

1. Review of MyBatis
Introduction from official documentation: MyBatis is an excellent persistence layer framework that supports customized SQL, stored procedures and advanced mapping. MyBatis avoids almost all JDBC code and manual setting of parameters and retrieval of result sets. MyBatis can use simple XML or annotations to configure and map native information, mapping interfaces and Java POJOs (Plain Old Java Objects, ordinary Java objects) into records in the database.

2. Introduction to Spring Data Jpa
Introduction from the official documentation: Spring Data JPA is part of the larger Spring Data family and can easily implement JPA-based repositories. This module handles enhanced support for JPA-based data access layer. It makes it easier to build Spring-driven applications that use data access technologies.

Detailed explanation: The reason for the birth of JPA is to integrate third-party ORM frameworks and establish a standard way. JDK is currently developing in this direction in order to achieve the unification of ORM, but it has not yet been fully realized. In the ORM framework, Hibernate is a large force. It is widely used, very convenient, and has strong capabilities. At the same time, Hibernate is well integrated with JPA. We can think of JPA as the standard. In fact, JPA is almost They are all interfaces, and the implementation is done by Hibernate. From a macro perspective, Hibernate runs very well under the unification of JPA.

The relationship between JPA and Hibernate is explained above, so what is Spring-data-jpa? In terms of integrating Spring with third parties, Spring has done the work of persistence, so there is a series of packages called Spring-Data. Including, Spring-Data-Jpa, Spring-Data-Template, Spring-Data-Mongodb, Spring-Data-Redis, and a private product, mybatis-spring, similar to the previous one, this is a third-party package integrated with mybatis. These are all things that persistence tools do.

Spring-data-jpa is introduced here, indicating integration with jpa.

When using persistence tools, there is usually an object to operate the database. It is called Session in native Hibernate, EntityManager in JPA, and SqlSession in MyBatis. The database is operated through this object. We generally look at it in terms of a three-tier structure. The Service layer does business logic processing, and the Dao layer deals with the database. In Dao, the above objects exist. So what functions does the ORM framework itself provide? The answer is basic CRUD. All basic CRUD frameworks are provided. It is very convenient for us to use. ORM does not provide processing at the business logic level. If we use the native framework, we will usually customize the business logic code and do it ourselves. Write the SQL statement and then execute it. At this time, the power of Spring-data-jpa is reflected. It provides all the capabilities provided by ORM. Spring-data-jpa also provides business logic functions that are not provided by the ORM framework, solving user needs in an all-round way. In the process of developing using Spring-data-jpa, we almost do not need to write a SQL statement for commonly used functions. Of course, spring-data-jpa also provides a way to write SQL by ourselves. (Mybatis-plus is also available, but from the perspective of Spring-Data-Jpa's fully automatic ORM, it is not as convenient as Spring-Data-Jpa for simple businesses)

3. Comparison between Spring Data JPA and MyBatis
Comparison between Spring Data JPA and MyBatis, that is, comparison between hibernate and MyBatis.

In terms of basic concepts and framework goals, the two frameworks are quite different. Hibernate is a more automated and advanced framework. After all, at the Java code level, most of the SQL writing is omitted, and instead the data of the relational database is operated in an object-oriented manner. MyBatis is a persistence layer framework that can flexibly write SQL statements and map SQL input parameters and query results into POJOs. Therefore, on the surface, hibernate is more convenient and more automated, while MyBatis is more flexible and free in writing Sql statements.

If you look at it at a higher level of abstraction, for data operations, hibernate is object-oriented, while MyBatis is relationship-oriented. Of course, you can also use hibernate to write relationship-oriented code and systems, but you will not get the various benefits of relationship-oriented, the biggest is the flexibility of writing SQL, and at the same time, you will also lose the meaning and benefits of object-oriented - in a word, neither fish nor fowl . So, what is the difference between object-oriented and relational models, and where is it reflected? In fact, the fields they face and the problems they want to solve are fundamentally different: object-oriented is committed to solving computer logic problems, while the relational model is committed to solving efficient data access problems.

mybatis: compact and convenient? , efficient, simple, direct, semi-automatic
Semi-automatic ORM framework,
compact: mybatis is the jdbc package
more popular in China .
Scenario: Used in a system with relatively complex business,

hibernate: powerful, convenient, efficient, (simple) complex, roundabout, fully automatic
Fully automatic ORM framework,
Powerful: based on ORM Mapping generates different SQL
which is more popular abroad.
Scenario: Used in a system with relatively simple business, with the popularity of microservices.

So much introduction, let’s take a look at the specific usage of Spring-Data-Jpa.

2. Use of Spring-Data-Jpa
JPA is just a specification, which means that JPA only defines some interfaces, and interfaces need to be implemented to work. So the bottom layer needs some kind of implementation, and Hibernate is the ORM framework that implements the JPA interface. In other words: JPA is a set of ORM specifications, and Hibernate implements the JPA specifications!

2.1 Hibernate example
pom.xml

<dependencies>
      <!-- junit4 -->
      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.13</version>
          <scope>test</scope>
      </dependency>
      <!-- hibernate对jpa的支持包 -->
      <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-entitymanager</artifactId>
          <version>5.4.32.Final</version>
      </dependency>

      <!-- Mysql and MariaDB -->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.26</version>
      </dependency>
      <!--openjpa-->
      <dependency>
          <groupId>org.apache.openjpa</groupId>
          <artifactId>openjpa-all</artifactId>
          <version>3.2.0</version>
      </dependency>

  </dependencies>


Entity class:

@Data
@Entity // As hibernate entity class
@Table(name = "tb_customer") // Mapping display
public class Customer {

    /**
     * @Id: Declare the configuration of the primary key
     * @GeneratedValue: Configure the generation strategy of the primary key
     * strategy
     * * GenerationType.IDENTITY: auto-increment, mysql
     * * The underlying database must support automatic growth (the underlying database supports automatic growth, for id Autoincrement)
     * GenerationType.SEQUENCE: sequence, oracle
     * * * The underlying database must support sequences
     * * GenerationType.TABLE: A mechanism provided by jpa to help us complete the primary key auto-increment in the form of a database table
     * * GenerationType.AUTO: The program automatically helps us choose the primary key generation strategy
     * @Column: Mapping relationship between configuration attributes and fields
     * name: The name of the field in the database table
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long custId; //Customer's primary key

    @Column(name = "cust_name")
    private String custName;//客户名称

    @Column(name="cust_address")
    private String custAddress;//客户地址
}


hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 配置数据库连接信息 -->
        <property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/springdata_jpa?characterEncoding=UTF-8</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>

        & lt;!-will record SQL default FALSE-& gt;
        & lt; propro name = & quot; show_sql & quot; & lt;/process & gt; < /A >
        have have have been sql being formatted.         >         <property name="dialect">org.hibernate.dialect.MySQL57InnoDBDialect</property>             !-- Configure dialect: select database type-->







        mapping>     </session-factory> </hibernate-configuration>



test

public class HibernateTest {

    // Session factory Session: a bridge between database session code and database
    private SessionFactory sf;
    @Before
    public void init() {         StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure("/hibernate.cfg.xml").build();         //2. Register based on service The class creates a metadata resource set, builds metadata and generates a generally unique session factory for the application         sf = new MetadataSources(registry).buildMetadata().buildSessionFactory();     }



    @Test //保存一个对象
    public void testC(){
        // session进行持久化操作
        try(Session session = sf.openSession()){
            Transaction tx = session.beginTransaction();
            Customer customer = new Customer();
            customer.setCustName("徐庶");
            session.save(customer);
            tx.commit();
        }

    }


    @Test //查找
    public void testR(){
        // session进行持久化操作
        try(Session session = sf.openSession()){
            Transaction tx = session.beginTransaction();
            Customer customer = session.find(Customer.class, 1L);
            System.out.println("=====================");
            System.out.println(customer);
            tx.commit();
        }
    }

    @Test //利用缓存查找对象
    public void testR_lazy(){
        // session进行持久化操作
        try(Session session = sf.openSession()){
            Transaction tx = session.beginTransaction();
            Customer customer = session.load(Customer.class, 1L);
            System.out.println("=====================");
            System.out.println(customer);
            tx.commit();
        }
    }
    
    @Test //更新
    public void testU(){
        // session进行持久化操作
        try(Session session = sf.openSession()){
            Transaction tx = session.beginTransaction();
            Customer customer = new Customer();
            //customer.setCustId(1L);
            customer.setCustName("徐庶");
            // 插入session.save()
            // 更新session.update();
            session.saveOrUpdate(customer);
            tx.commit();
        }
    }


    @Test //删除
    public void testD(){
        // session进行持久化操作
        try(Session session = sf.openSession()){
            Transaction tx = session.beginTransaction();
            Customer customer = new Customer();
            customer.setCustId(2L);
            session.remove(customer);
            tx.commit();
        }
    }

    @Test //自定义sql
    public void testR_HQL(){
        // session进行持久化操作
        try(Session session = sf.openSession()){
            Transaction tx = session.beginTransaction();
            String hql=" FROM Customer where custId=:id";
            List<Customer> resultList = session.createQuery(hql, Customer.class)
                    .setParameter("id",1L)
                    .getResultList();
            System.out.println(resultList);
            tx.commit();
        }
    }
}


2.2Jpa example
Added META-INF\persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun .com/xml/ns/persistence" version="2.0">
    <!--The persistence-unit node needs to be configured
        Persistence unit :
            name: persistence unit name
            transaction-type: transaction management method
                    JTA: distributed transaction management a>         /span>         ;     <persistence-unit name="hibernateJPA" transaction-type=" RESOURCE_LOCAL">     -->
                    RESOURCE_LOCAL:Local transaction management





        ; -- Database information                 Username, javax.persistence.jdbc.user                 Password, javax.persistence.jdbc.password                 Driver, javax.persistence.jdbc.driver                 Database address javax.persistence.jdbc.url             -& gt;             & lt ;property name="javax.persistence.jdbc.user" value="root"/>             <property name="javax.persistence.jdbc.password" value=" ;123456"/>             >             <property name="javax.persistence.jdbc.url"










            & lt;!-Configure the configuration information of the JPA implementation party (Hibernate)
                Display SQL: FALSE | TRUE
                Automatically create a database list: Hibernate .hbm2ddl.auto
                        Create: Create a database table when the program is runtime (if there is a table, first delete the table before creating) Update: Create a table when the program is runtime (if the program is running (if the program is running (if the program is runtime There is a table, the table will not be created)                         use   using using using         using ’ ’ s ’ ’ s ’         through ’ through ’ s ’ through ’ through ‐‐ ‐‐‐‐‐ ​ to "hibernate.show_sql" value="true" />             ;             <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />





        </properties>
    </persistence-unit>

    <persistence-unit name="openJpa" transaction-type="RESOURCE_LOCAL">
        <!--jpa的实现方式 -->
        <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>

        =2>                                                                                     Database information                 Username, javax.persistence.jdbc.user                 Password, javax.persistence.jdbc.password                 Driver, javax.persistence.jdbc.driver                 name="javax.persistence.jdbc.user" value="root"/>             <property name="javax.persistence.jdbc.password" value="123456" ;/& gt;             & lt; Property name = & quot; javax.persisistence.jdbc.driver & quot; value = & quot; com.mysql.cjdbc.driver & quot; /& gt; < i=13>












            Database list-& gt;             & lt; proprity name = & quot; openjpa.jdbc.SynChronizeMappings & quot; value = & QuotSChema (ForeIGNKEYS = true) & quot;/& gt;        






test

Tip: It is called Session in Hibernate and EntityManager in JPA.

4 states of jpa objects

Temporary state: Just created, ∙ has no relationship with the entityManager, has not been persisted, and is not an object in the entityManager
Persistent state: ∙ has a relationship with the entityManager and has been Persistence, you can treat the persistent state as a real database record.
Deletion state: execute the remove method, before the transaction is committed.
Free state: The free state is the state of the entity after the transaction is committed after it is submitted to the database, because the transaction has been submitted. At this time, the attributes of the entity can be changed as you wish, and they will not be synchronized to the database, because the detached entity is an unmanaged child and is not in the persistence context. public void persist(Object entity)

The persist method can convert the instance to managed state. After calling the flush() method or submitting the transaction, the instance will be inserted into the database.

For instance A in different states, persist will produce the following operations:
1. If A is an entity in new state, it will be converted to managed state;     }         tx.commit();         em. persist(customer); // Save and keep the entity in Managed state         customer.setCustName("Zhang San");         Customer customer = new Customer();         tx.begin() ;         EntityTransaction tx = em.getTransaction();         EntityManager em = factory.createEntityManager();     public void testC(){     @Test     }          factory= Persistence.createEntityManagerFactory("hibernateJPA");     public void before(){     @Before     EntityManagerFactory factory; public class JpaTest { JPA implementations. 4. If A is an entity in the detached state, this method will throw an IllegalArgumentException exception. The specific exception depends on different 3. If A is an entity in the removed (deleted) state, it will be converted to a controlled state;
2. If A is a managed entity, its state will not change. However, the system will still perform an INSERT operation in the database;










    









    // 立即查询
    @Test
    public void testR(){
        EntityManager em = factory.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        Customer customer = em.find(Customer.class, 1L);
        System.out.println("========================");
        System.out.println(customer);
        tx.commit();
    }


    // 延迟查询
    @Test
    public void testR_lazy(){
        EntityManager em = factory.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        Customer customer = em.getReference(Customer.class, 1L);
        System.out.println("========================");
        System.out.println(customer);
        tx.commit();
    }


    @Test
    public void testU(){
        EntityManager em = factory.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();
        Customer customer = new Customer();
        customer.setCustId(5L);
        customer.setCustName("王五");
        /*
        *
        Change update Do not update if there is no change         * If no primary key is specified:         * Insert         * */     }         tx.commit();         em.merge(customer);







    @Test//自定义sql
    public void testU_JPQL(){
        EntityManager em = factory.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        String jpql="UPDATE Customer set custName=:name where custId=:id";
        em.createQuery(jpql)
                .setParameter("name","李四")
                .setParameter("id",5L)
                        .executeUpdate();

        tx.commit();
    }


    @Test
    public void testU_SQL(){
        EntityManager em = factory.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        String sql="UPDATE tb_customer set cust_name=:name where id=:id";
        em.createNativeQuery(sql)
                .setParameter("name","王五")
                .setParameter("id",5L)
                .executeUpdate();

        tx.commit();
    }


    @Test
    public void testD(){
        EntityManager em = factory.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        Customer customer = em.find(Customer.class,5L);
        em.remove(customer);
        tx.commit();
    }
}


1
104
105
106
3.1Spring Data JPA instance
Let’s implement an example based on Spring Data JPA to feel the difference from using it alone before:
Dependencies:
Parent pom :

 <!--统一管理SpringData子项目的版本-->
   <dependencyManagement>
       <dependencies>
           <dependency>
               <groupId>org.springframework.data</groupId>
               <artifactId>spring-data-bom</artifactId>
               <version>2021.1.0</version>
               <scope>import</scope>
               <type>pom</type>
           </dependency>
       </dependencies>
   </dependencyManagement>

子pom:

 <dependency>
     <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
    </dependency>
    <!-- junit4 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
    <!-- hibernate对jpa的支持包 -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>5.4.32.Final</version>
    </dependency>
    <!-- Mysql and MariaDB -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.26</version>
    </dependency>
    <!--连接池-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.8</version>
    </dependency>
    <!--spring-test -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.10</version>
        <scope>test</scope>
    </dependency>
    <!-- querydsl -->
    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-jpa</artifactId>
        <version>${querydsl.version}</version>
    </dependency>


42
SpringDataJPAConfig

@Configuration // Mark the current class as the configuration class =xml configuration file
@EnableJpaRepositories(basePackages="com.tuling.repositories") // Start jpa <jpa: repositories
@EnableTransactionManagement // Enable transaction
public class SpringDataJPAConfig {


    /*
    *  <!--数据源-->
    <bean class="com.alibaba.druid.pool.DruidDataSource" name="dataSource">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/springdata_jpa?characterEncoding=UTF-8"/>
    </bean>
    * */
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/springdata_jpa?characterEncoding=UTF-8");

        return  dataSource;

    }

    /*
    *  <!--EntityManagerFactory-->
    <bean name="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaVendorAdapter">
            <!--Hibernate实现-->
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--生成数据库表-->
                <property name="generateDdl" value="true"></property>
                <property name="showSql" value="true"></property>
            </bean>
        </property>
        <!--设置实体类的包-->
        <property name="packagesToScan" value="com.tuling.pojo"></property>
        <property name="dataSource" ref="dataSource" ></property>
    </bean>
    * */
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);
        vendorAdapter.setShowSql(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("com.tuling.pojo");
        factory.setDataSource(dataSource());
        return factory;
    }

    /*
    * <bean class="org.springframework.orm.jpa.JpaTransactionManager" name="transactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"></property>
    </bean>
    * */
    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {

        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }
}



XML

<?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:jpa="http://www.springframework.org/schema/data/jpa" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/jpa
    https://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--用于整合jpa  @EnableJpaRepositories -->
    <jpa:repositories base-package="com.tuling.repositories"
                      entity-manager-factory-ref="entityManagerFactory"
                      transaction-manager-ref="transactionManager"
    />


    <!--EntityManagerFactory-->
    <bean name="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaVendorAdapter">
            <!--Hibernate实现-->
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--生成数据库表-->
                <property name="generateDdl" value="true"></property>
                <property name="showSql" value="true"></property>
            </bean>
        </property>
        <!--设置实体类的包-->
        <property name="packagesToScan" value="com.tuling.pojo"></property>
        <property name="dataSource" ref="dataSource" ></property>
    </bean>

    <!--数据源-->
    <bean class="com.alibaba.druid.pool.DruidDataSource" name="dataSource">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/springdata_jpa?characterEncoding=UTF-8"/>
    </bean>

    <!--声明式事务-->
    <bean class="org.springframework.orm.jpa.JpaTransactionManager" name="transactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"></property>
    </bean>

    <!--Start annotation-driven declarative transactions-->
    <tx:annotation-driven transaction-manager="transactionManager"></ tx:annotation-driven>

</beans>


poo

@Data
@Entity // As hibernate entity class
@Table(name = "tb_customer") // Mapping display
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long custId; //客户的主键

    @Column(name = "cust_name")
    private String custName;//客户名称

    @Column(name="cust_address")
    private String custAddress;//客户地址
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CustomerRepository
Use Spring Data RepositoriesAbstract objects that are small and durable Amount of money.

CrudRepository
1
2 // Used to insert and modify. If there is a primary key, it will be modified. If not, it will be added.
3 // Get the id that is automatically incremented after insertion, and get the return value
4 <S extends T> S save(S entity);
5
6 // Save multiple entities through collections
7 <S extends T> Iterable<S> saveAll(Iterable<S> entities);
8 // Query the entity by primary key
9 Optional<T> findById(ID id);
10 // Query whether it exists by primary key and return boolean 13 Iterable<T> findAll(); 27 void deleteAll(); 26 // Delete all 25 void deleteAll(Iterable<? extends T> entities); 24 // Delete multiple incoming collection entities 23 void deleteAllById(Iterable<? extends ID> ids); 22 // Delete multiple 21 void delete(T entity); 20 //Delete based on entity 19 void deleteById(ID id); 18 // Delete based on id 17 long count(); 16 // Query the total quantity 15 Iterable<T> findAllById(Iterable<ID> ids); 14 // Query multiple entities through the primary key of the collection, and return the collection 12 // Query all
11 boolean existsById(ID id);
















public interface CustomerRepository extends PagingAndSortingRepository<Customer, Long> {
}
1
2
测试

@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringdataJpaTest {

    @Autowired
    CustomerRepository repository;
    @Test
    public  void testR(){
        Optional<Customer> byId = repository.findById(1L);
        System.out.println(byId.orElse(null));
    }

    @Test
    public  void testC(){
        Customer customer = new Customer();
        customer.setCustName("李四");
        System.out.println(repository.save(customer));
    }

    @Test
    public  void testD(){
        Customer customer = new Customer();
        customer.setCustId(3L);
        customer.setCustName("李四");
        repository.delete(customer);
    }
    @Test
    public  void testFindAll(){
        Iterable<Customer> allById = repository.findAllById(Arrays.asList(1L, 7L, 8L));
        System.out.println(allById);
    }

}


34
3.1.1 Paging
On top of CrudRepository, there is a PagingAndSortingRepository abstraction that adds additional methods to simplify paging entities Visit:

@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringDataJpaPagingAndSortTest
{
    // jdk动态代理的实例
    @Autowired(required=false)
    CustomerRepository repository;

    @Test
    public void insertCustomer() {
        for (int i = 20; i < 50; i++) {
            Customer customer = new Customer();
            customer.setCustName("张三"+i);
            customer.setCustAddress("北京");
            repository.save(customer);
        }

    }

    @Test
    public  void testPaging(){
        Page<Customer> all = repository.findAll(PageRequest.of(0, 2));
        System.out.println(all.getTotalPages());
        System.out.println(all.getTotalElements());
        System.out.println(all.getContent());

    }

    @Test
    public  void testSort(){
        Sort sort = Sort.by("custId").descending();
        Iterable<Customer> all = repository.findAll(sort);
        System.out.println(all);
    }
     
    @Test
    public  void testSortTypeSafe(){
        Sort.TypedSort<Customer> sortType = Sort.sort(Customer.class);
        Sort sort = sortType.by(Customer::getCustId).descending();
        Iterable<Customer> all = repository.findAll(sort);
        System.out.println(all);

    }
}


1
2
3



3.1.2 Self-determined operation
1.jpql (primitive SQL): @Query

If the query returns a single entity, use pojo to receive it. If it returns multiple entities, it needs to be received through a collection.

Parameter setting method

Index: ?Number
Named: :Parameter name Combined with the @Param annotation to specify the parameter name
Addition, deletion and modification:

Add transaction support:
If it is an insertion method: it must only be supported under hibernate (Insert into
…select)< /span> Supported query method subject keywords (prefix) 2. Specify method name 2 1 @Modifying // Notify springdatajpa that the operation is addition, deletion and modification
@Transactional // Usually declared on the business logic layer




Determines the role of the current method
Only supports query and deletion
Please refer to the official documentation for details

3.Query by Example

Only supports query

does not support nested or grouped attribute constraints, such as firstname = ? 0 or (firstname = ?1
and lastname = ?2).
only supports string start/contains/ends/regex matching and exact matching of other attribute types Match
.
Implementation:
1. Inherit Repository from QueryByExampleExecutor

public interface CustomerQBERepository
        extends PagingAndSortingRepository<Customer, Long>
        , QueryByExampleExecutor<Customer> {

}

2. 测试代码

@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class QBETest {

    // Instance of jdk dynamic proxy
    @Autowired
    CustomerQBERepository repository;

    /**
     * Simple example Customer name Customer address dynamic query
     */
    @Test
    public void test01(){

        // 查询条件
        Customer customer=new Customer();
        customer.setCustName("徐庶");
        customer.setCustAddress("BEIJING");
        // 通过Example构建查询条件
        Example<Customer> example = Example.of(customer);
        List<Customer> list = (List<Customer>) repository.findAll(example);
        System.out.println(list);
    }


    /**
     * Restriction of conditions through matcher
     * Simple example of customer name and customer address dynamic query
     */
    @Test
    public void test02(){

        // 查询条件
        Customer customer=new Customer();
        customer.setCustName("庶");
        customer.setCustAddress("JING");

        // Set conditional behavior through matcher
        ExampleMatcher matcher = ExampleMatcher.matching()
                //.withIgnorePaths("custName" ) // Set ignored attributes
                //.withIgnoreCase("custAddress") // Set ignored case
                //.withStringMatcher(ExampleMatcher.StringMatcher. ENDING); // All condition strings are matched at the end
                .withMatcher("custAddress",m -> m.endsWith().ignoreCase()); // For a single Conditional restrictions will make withIgnoreCase invalid and need to be set separately
                //.withMatcher("custAddress", ExampleMatcher.GenericPropertyMatchers.endsWith().ignoreCase());

        // 通过Example构建查询条件
        Example<Customer> example = Example.of(customer,matcher);
        List<Customer> list = (List<Customer>) repository.findAll(example);
        System.out.println(list);
    }
}



4.Specifications
Previously, Query by Example could only set conditions for strings. If you want to support all types, you can use Specifications
Implementation:

 public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {   } 1 2 2. Implementation of passing in Specification: Combined with lambda expression Formula



repository.findAll((Specification<Customer>)
    (root, query, criteriaBuilder) ‐>
    {         // Todo...                                                                                                                                                                                                                                              /span> 1 2 3 4 5< /span> Predicate (Expression): Detailed description of each query condition between in…) = where CriteriaBuilder: What is the relationship between the conditions, how to generate a query condition, and what type is each query condition (> CriteriaQuery: Which fields to query, what is the order = combination (order by . where ) Root: Which table to query (associated query) = from 7 6















@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpecificationTest {

    // jdk动态代理的实例
    @Autowired
    CustomerSpecificationsRepository repository;
    @Test
    public  void testR(){
        List<Customer> customer = repository.findAll(new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                // root from Customer  , 获取列
                // CriteriaBuilder where 设置各种条件  (> < in ..)
                // query  组合(order by , where)
                return null;
            }
        });
        System.out.println(customer);
    }

    @Test
    public  void testR5(){
        Customer params=new Customer();
        //params.setCustAddress("BEIJING");
        params.setCustId(0L);
        params.setCustName("徐庶,王五");
        List<Customer> customer = repository.findAll(new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

                // root from Customer  , 获取列
                // CriteriaBuilder where 设置各种条件  (> < in ..)
                // query  组合(order by , where)
                Path<Long> custId = root.get("custId");
                Path<String> custName = root.get("custName");
                Path<String> custAddress = root.get("custAddress");

                using   use with   using   using   using   using           using using ’ ’ s ’ ’ s ‐ ‐ ‐ ‐ ‐ ​ ​ ​ ​ ​                                   to  > If (! StringUtils.isempty (params.getCustadress ())) {) {                     list.add(cb.equal(custAddress, "BEIJING")); ()>-1){                     list.add(cb.greaterThan(custId, 0L));






                if(!StringUtils.isEmpty(params.getCustName())) {
                    CriteriaBuilder.In<String> in = cb.in(custName);
                    in.value("徐庶").value("王五");
                    list.add(in);
                }
                Predicate and = cb.and(list.toArray(new Predicate[list.size()]));
                Order desc = cb.desc(custId);
                return query.where(and).orderBy(desc).getRestriction();
            }
        });
        System.out.println(customer);
    }
}


5.Querydsl
Official website address
QueryDSL is a general query framework based on the ORM framework or SQL platform. With QueryDSL, queries can be built as a common API on any supported ORM framework or SQL platform.

JPA is the primary integration technology for QueryDSL and is an alternative to JPQL and Criteria queries. Currently QueryDSL supports platforms including JPA, JDO, SQL, Mongodb, etc.

The Querydsl extension allows us to code query methods in a chained manner. This extension requires an interface QueryDslPredicateExecutor, which defines many query methods.

If the interface inherits the interface, you can use the various methods provided by the interface.

public interface QuerydslPredicateExecutor<T> {
    Optional<T> findOne(Predicate predicate);

    Iterable<T> findAll(Predicate predicate);

    Iterable<T> findAll(Predicate predicate, Sort sort);

    Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);

    Iterable<T> findAll(OrderSpecifier<?>... orders);

    Page<T> findAll(Predicate predicate, Pageable pageable);

    long count(Predicate predicate);

    boolean exists(Predicate predicate);

    <S extends T, R> R findBy(Predicate predicate, Function<FetchableFluentQuery<S>, R> queryFunction);
}


Introduce dependencies

 <!-- querydsl -->
 <dependency>
     <groupId>com.querydsl</groupId> This plug-in is to allow the program to automatically generate query type (query entity, the naming method is: "Q" + corresponding entity name). Add plug-in  </dependency>      <version>${querydsl.version}</version>
     <artifactId>querydsl-jpa</artifactId>




<build>
        <plugins>
            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>${apt.version}</version>
                <dependencies>
                    <dependency>
                        <groupId>com.querydsl</groupId>
                        <artifactId>querydsl-apt</artifactId>
                        <version>${querydsl.version}</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources/queries</outputDirectory>
                            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                            <logOnlyOnError>true</logOnlyOnError>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>


test

@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class QueryDSLTest {

    
    @Autowired
    CustomerQueryDSLRepository repository;

    @Test
    public  void test01() {
        QCustomer customer = QCustomer.customer;
        // 通过Id查找
        BooleanExpression eq = customer.custId.eq(1L);
        System.out.println(repository.findOne(eq));

    }


    /**
     * Query customer name range (in)
     * id >greater than
     * Address Accurate
     */
    @Test
    public void test02() { / Xu Shu", "Wang Wu")                 .and(customer.custId.gt(0L))                 .and(customer.custAddress.eq( "BEIJING"));




        System.out.println(repository.findOne(and));

    }

    /**
     * Query customer name range (in)
     * id >greater than
     * Address Accurate
     */
    @Test
    public void test03() {

        Customer params=new Customer();
        Params.setCustAddress("BEIJING");
        Params.setCustId(0L);         BooleanExpression expression = customer.isNotNull().or(customer.isNull());         // Initial conditions Similar to the condition that 1=1 is always true         QCustomer customer = QCustomer.customer;
        params.setCustName("Xu Shu, Wang Wu");


        expression=params.getCustId()>-1?
                expression.and(customer.custId.gt(params.getCustId())):expression;
        expression=!StringUtils.isEmpty( params.getCustName())?
                expression.and(customer.custName.in(params.getCustName().split(","))):expression;
        expression=!StringUtils.isEmpty( params.getCustAddress())?
                expression.and(customer.custAddress.eq(params.getCustAddress())):expression;

        System.out.println(repository.findAll(expression));

    }


    // Solve thread safety issues
    @PersistenceContext
    EntityManager em;
    /**
     * Custom column query and grouping
     * Need to use the original ecological method (Specification)
     * Query through Repository, both columns and tables Is fixed
     */
    @Test
    public void test04() {         JPAQueryFactory factory = new JPAQueryFactory(em);         QCustomer customer = QCustomer.customer;         // Build a query based on QueryDSL         . .where(customer.custId.eq(1L))                 . . . orderBy(customer.custId.desc());






        // 执行查询
        List<Tuple> fetch = tupleJPAQuery.fetch();
        // 处理返回数据
        for (Tuple tuple : fetch) {
            System.out.println(tuple.get(customer.custId));
            System.out.println(tuple.get(customer.custName));
        }
    }

    @Test
    public  void test05() {
        JPAQueryFactory factory = new JPAQueryFactory(em);
        QCustomer customer = QCustomer.customer;
        // 构建基于QueryDSL的查询
        JPAQuery<Long> longJPAQuery = factory.select(
                        customer.custId.sum())
                .from(customer)
                //.where(customer.custId.eq(1L))
                .orderBy(customer.custId.desc());
        // 执行查询
        List<Long> fetch = longJPAQuery.fetch();
        // 处理返回数据
        for (Long sum : fetch) {
            System.out.println(sum);
        }
    }
}


3.1.3 Multi-table association operation
One-to-one
1. Configuration management relationship
@OneToOne< /span>
@JoinColumn(name="foreign key field name")

@OneToOne
@JoinColumn(name="customer_id")
private Customer customer;
1
2
3
@Entity     // 作为hibernate 实体类
@Table(name = "tb_customer")       // 映射的表明
@Data
@EntityListeners(AuditingEntityListener.class)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long custId; //客户的主键

    @Column(name = "cust_name")
    private String custName;//客户名称

    @Column(name="cust_address")
    private String custAddress;//客户地址


    // One-way association one-to-one
    /*
    * cascade set association operation
    * ALL, All persistence operations
        PERSIST Only inserts will perform associated operations
        MERGE, Only modifications will perform associated operations
        REMOVE, Only deletion will perform the associated operation
      fetch sets whether to load lazily
          EAGER loads immediately (default)
          LAZY lazily loads (until The query will be performed only when the object is used, because not all associated objects need to be used)
      orphanRemoval association removal (usually used when modifying)
          Once the associated data is set to null, or changed to other associated data, if you want to delete the associated data, you can set true
      Optional Limit the associated object to not be null
            using   using           ’ s ’ s ’ s through using ‐ ‐ ‐ ‐ ‐ ,                                                                                                               to   to   to        . a>     @OneToOne(mappedBy = "customer",     **/         Value = the other party’s associated attribute name     // Set the field name of the foreign key< a i=20> @JoinColumn(name="account_id")     private Account account; }









test

@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class OneToOneTest {
    @Autowired
    CustomerRepository repository;

    // 插入
    @Test
    public void testC(){
        // 初始化数据
        Account account = new Account();
        account.setUsername("xushu");
        Customer customer = new Customer();
        customer.setCustName("徐庶");
        customer.setAccount(account);
        account.setCustomer(customer);
        repository.save(customer);
    }


    // Insert
    @Test
    // Why does lazy loading need to configure transactions:
    // When passed After the repository calls the query method, the session will be closed immediately. Once the session is completed, you cannot query.
    // After adding a transaction, the session will not be closed until the transaction method is executed a>     }         System.out.println(customer.get()); // toString         System.out.println("== ===============");         Optional<Customer> customer = repository.findById(3L); // Only query the customer, session is closed     public void testR(){
    @Transactional(readOnly = true)




    @Test
    public void testD(){
        repository.deleteById(1L);
    }

    @Test
    public void testU(){
        Customer customer = new Customer();
        customer.setCustId(16L);
        customer.setCustName("徐庶");
        customer.setAccount(null);
        repository.save(customer);
    }
}



Differences
The difference between these two settings is that the relationship is broken. For example, when the address field is set to null or another Address object.

If orphanRemoval = true is specified, disconnected Address instances are automatically removed. This is useful for cleaning up without a related object (e.g. address) that shouldn't have a reference from the owner object (e.g. employee) .
If you only specify cascade = CascadeType.REMOVE, no automatic operation will be performed because breaking the relationship is not a delete operation

One-to-many
1. Configuration management relationship
@OneToMany
@JoinColumn(name="customer_id ”)

// One-to-many
// fetch defaults to lazy loading Advantages of lazy loading (improves query performance)
@OneToMany(cascade = CascadeType .ALL,fetch = FetchType.LAZY)
@JoinColumn(name="customer_id")
private List<Message> messages;

2. Configure related operations


/***
 * 一(客户)对多(信息)
 */
@Entity
@Table(name="tb_message")
@Data
public class Message {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String info;


    // 多对一
    @ManyToOne(cascade = {CascadeType.PERSIST,CascadeType.REMOVE})
    @JoinColumn(name="customer_id")
    private Customer customer;

    // It must be there, otherwise there will be problems with the query

    public Message() {
    }
    public Message(String info) {
        this.info = info;
    }

    public Message(String info, Customer customer) {
        this.info = info;
        this.customer = customer;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", info='" + info + '\'' +
                ", customerId=" + customer.getCustId() +
                ", customerName=" + customer.getCustName() +
                '}';
    }
}



Many-to-one is similar to one-to-many, so no demonstration will be given
Many-to-many
1. Configuration management relationship
@ManyToMany
@JoinColumn(name="customer_id")

 // One-way many-to-many
@ManyToMany(cascade = CascadeType.ALL)
/*The intermediate table needs to be maintained through @JoinTable Key: (will be automatically generated if not set)
* name specifies the name of the intermediate table
* joinColumns sets the foreign key name of this table
* inverseJoinColumns sets the foreign key name of the associated table
* */
@JoinTable(
        name="tb_customer_role" ;,
        joinColumns = {@JoinColumn(name="c_id")},
        inverseJoinColumns = {@JoinColumn(name="r_id")}< /span> 2. Configure association operations private List<Role> roles;
)


/**
 * 多(用户)对多(角色)
 */
@Entity
@Table(name="tb_role")
@Data
public class Role {

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

    @Column(name="role_name")
    private String rName;

    public Role(String rName) {
        this.rName = rName;
    }

    public Role(Long id, String rName) {
        this.id = id;
        this.rName = rName;
    }

    public Role() {
    }

    @ManyToMany(cascade = CascadeType.ALL)
    private List<Role> roles;
}



test

ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ManyToManyTest {
    @Autowired
    CustomerRepository repository;
    @Autowired
    RoleRepository roleRepository;

    @Test
    public void testSave(){
        List<Role> roles = new ArrayList<>();
        roles.add(new Role("管理员"));
        roles.add(new Role("普通用户"));
        Customer customer = new Customer();
        customer.setCustName("诸葛");
        customer.setRoles(roles);
        repository.save(customer);
    }

    // Save
    /*
    1. If you want to use the existing associated data, you need to find it from the database (persistent state). Otherwise, it will prompt that the free state cannot be persisted
    2. If a business method has multiple persistence operations, remember to add @Transactional, otherwise the same session cannot be shared
    3 . @Transactional is used in the unit test. If there are additions, deletions and modifications, be sure to add @Commit
    4. The unit test will think that your transaction method @Transactional is just a test, it will not To submit a transaction for you, you need to add @Commit
     separately */
    @Test
    @Transactional
    @Commit
    public void testC() {         List<Role> roles=new ArrayList<>();         Roles.add(roleRepository.findById(1L).get()); a>     }         repository.save(customer);         customer.setRoles(roles);         customer .setCustName("Zhuge");         Customer customer = new Customer();         roles.add(roleRepository.findById(2L).get());







    @Test
    @Transactional(readOnly = true)
    public void testR() {
        System.out.println(repository.findById(14L));
        //repository.save(customer);
    }

    /*
    * Note to add
    * @Transactional
        @Commit
      Many-to-many is actually not suitable for deletion, because often data may not only be associated with the current end but also be associated with the other end. In this case, deletion will result in: ConstraintViolationException.
      * To delete, make sure there is no additional data association at the other end
    * */
    @Test< a i=8> @Transactional     @Commit     public void testD() {         Optional<Customer> customer = repository.findById(14L);         repository.delete(customer.get());     } }








乐观锁
hibernate
幐发发发发明

private @Version Long version;
1
三、SpringBoot整合Spring-Data-Jpa
依赖

<dependencies>
      <!--data-jpa的场景启动器-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <scope>runtime</scope>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
      </dependency>
  </dependencies>

  <build>
      <plugins>
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
      </plugins>
  </build>


Common configuration


# Database table generation strategy
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql: //localhost:3306/springdata_jpa?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Whether to display sql in the console
spring.jpa. show-sql= true 
spring.jpa.properties.hibernate.format_sql=true
server.port=8088

Optional Configuration
Hibernate official document
SpirngDataJpa official document

The rest is the normal development process, persistence layer, business layer, control layer

Guess you like

Origin blog.csdn.net/2301_79354153/article/details/134772511