springdata Learning Log

Keywords: Druid Hibernate Spring SQL

SpringData JPA

springdata Learning Log - day1

1. Basic introduction of Spring-data-jpa

  1. spring-data jpa represents the integration with jpa, and hibernate implementation standard is provided by JPA (interface).
  2. In native hibernate, the object of database operation is Session, in JPA, Entity Manager, and in MyBatis, SqlSession.
  3. In ORM framework, basic CRUD functions will be provided. If using the native framework, the general business logic code will be customized and SQL statements will be written by itself. The strong point of spring-data jpa is that it can almost realize the business SQL implementation of complex logic without writing an sql.

2. Integration with Spring

`<?xml version="1.0" encoding="UTF-8"?>

<!-- Database Connection -->
<context:property-placeholder location="classpath:your-config.properties" ignore-unresolvable="true" />
<!-- service package -->
<context:component-scan base-package="your service package" />
<!-- Use cglib Dynamic proxy -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- Supporting annotated declarative transactions -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<!--base-package Express dao Interface location, repository-impl-postfix The property represents the suffix end character of an interface's implementation class. spring-data-jpa The habit is that interfaces and implementation classes need to be placed in the same package. UserRepositoryImpl We don't need to specify implementations when defining this class UserRepository Interface, according to spring-data-jpa The relationship between them can be judged automatically.-->

<jpa:repositories base-package="your dao package" repository-impl-postfix="Impl" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager" />
<!-- Entity Manager -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <!--Loaded entity entity-->
    <property name="packagesToScan" value="your entity package" />
    <property name="persistenceProvider">
        <bean class="org.hibernate.ejb.HibernatePersistence" />
    </property>
    <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.MySQL5InnoDBDialect" />
            <!-- <property name="showSql" value="true" /> -->
        </bean>
    </property>
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
    <property name="jpaPropertyMap">
        <map>
            <entry key="hibernate.query.substitutions" value="true 1, false 0" />
            <entry key="hibernate.default_batch_fetch_size" value="16" />
            <entry key="hibernate.max_fetch_depth" value="2" />
            <entry key="hibernate.generate_statistics" value="true" />
            <entry key="hibernate.bytecode.use_reflection_optimizer" value="true" />
            <entry key="hibernate.cache.use_second_level_cache" value="false" />
            <entry key="hibernate.cache.use_query_cache" value="false" />
        </map>
    </property>
</bean>

<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- data source -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="driverClassName" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${userName}" />
    <property name="password" value="${password}" />
    <property name="initialSize" value="${druid.initialSize}" />
    <property name="maxActive" value="${druid.maxActive}" />
    <property name="maxIdle" value="${druid.maxIdle}" />
    <property name="minIdle" value="${druid.minIdle}" />
    <property name="maxWait" value="${druid.maxWait}" />
    <property name="removeAbandoned" value="${druid.removeAbandoned}" />
    <property name="removeAbandonedTimeout" value="${druid.removeAbandonedTimeout}" />
    <property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />
    <property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />
    <property name="validationQuery" value="${druid.validationQuery}" />
    <property name="testWhileIdle" value="${druid.testWhileIdle}" />
    <property name="testOnBorrow" value="${druid.testOnBorrow}" />
    <property name="testOnReturn" value="${druid.testOnReturn}" />
    <property name="poolPreparedStatements" value="${druid.poolPreparedStatements}" />
    <property name="maxPoolPreparedStatementPerConnectionSize" value="${druid.maxPoolPreparedStatementPerConnectionSize}" />
    <property name="filters" value="${druid.filters}" />
</bean>

<!-- affair -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" />
        <tx:method name="get*" read-only="true" />
        <tx:method name="find*" read-only="true" />
        <tx:method name="select*" read-only="true" />
        <tx:method name="delete*" propagation="REQUIRED" />
        <tx:method name="update*" propagation="REQUIRED" />
        <tx:method name="add*" propagation="REQUIRED" />
        <tx:method name="insert*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>
<!-- Transaction entry -->
<aop:config>
    <aop:pointcut id="allServiceMethod" expression="execution(* your service implements package.*.*(..))" />
    <aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice" />
</aop:config>

`

3. Usage and details

  1. XXX Repository Impl does not need to implement the XXX Repository interface, because the latter inherits Jpa Repository. If our User Repository Impl implements the User Repository interface, the consequence is that we have to rewrite all the methods in it, which is stipulated in Java grammar. As a result, tragedy arises. We have a lot of @Override methods in User Repository Impl. Obviously not. The conclusion is that we don't have to write implements here.
  2. for instance:
First step-Building tables
//Step 2 - Entity class
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private String password;
    private String birthday;
    // getter,setter
}
//Step 3 - Write Interface
public interface UserRepository extends JpaRepository<User, Integer>{}
//So far, the basic CRUD of User is ok.

//Test:

public class UserRepositoryTest {
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    public void baseTest() throws Exception {
        User user = new User();
        user.setName("Jay");
        user.setPassword("123456");
        user.setBirthday("2008-08-08");
        userRepository.save(user);
//        userRepository.delete(user);
//        userRepository.findOne(1);
    }
}

3. Naming Specification and Principle of SpringData Method

Define in the UserRepository interface:
	User findByNameAndPassword(String name, String password);
The translated sql statement:
	select * from user where name = ? and password = ?;

The principle is that spring-data-jpa automatically generates sql statements according to the name of the method. We just need to follow the rules defined by the method. The method findByName AndPassword, spring-data-jpa, stipulates that:
Methods start with findBy, where part of sql is Name AndPassword, which can be fuzzily queried by adding keywords like after attributes, such as User findByNameLike(String name); the generated sql is select * from user where name like =?.

4. Dynamic Query and Paging, etc.
a. Using JPQL, similar to Hibernate's HQL
It was mentioned earlier that a common class UserRepository Impl was created under the same package of the UserRepository interface to represent the implementation class of this class. It was also mentioned that this class was not needed at all, but it had to be used in a JPQL way.

public class StudentRepositoryImpl {
    
    @PersistenceContext
    private EntityManager em;
    @SuppressWarnings("unchecked")
    public Page<Student> search(User user) {
        String dataSql = "select t from User t where 1 = 1";
        String countSql = "select count(t) from User t where 1 = 1";
        
        if(null != user && !StringUtils.isEmpty(user.getName())) {
            dataSql += " and t.name = ?1";
            countSql += " and t.name = ?1";
        }
        
        Query dataQuery = em.createQuery(dataSql);
        Query countQuery = em.createQuery(countSql);
        
        if(null != user && !StringUtils.isEmpty(user.getName())) {
            dataQuery.setParameter(1, user.getName());
            countQuery.setParameter(1, user.getName());
        }long totalSize = (long) countQuery.getSingleResult();
        Page<User> page = new Page();
        page.setTotalSize(totalSize);
        List<User> data = dataQuery.getResultList();
        page.setData(data);
        return page;
    }
}

b. Using JPA dynamic interface, splicing sql by type checking

public interface JpaSpecificationExecutor<T> 

for instance:>

@Service
public class StudentServiceImpl extends BaseServiceImpl<Student> implements StudentService {
    
    @Autowired
    private StudentRepository studentRepository;
    
    @Override
    public Student login(Student student) {
        return studentRepository.findByNameAndPassword(student.getName(), student.getPassword());
    }

    @Override
    public Page<Student> search(final Student student, PageInfo page) {
        return studentRepository.findAll(new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                
                Predicate stuNameLike = null;//The parameter object behind where
                if(null != student && !StringUtils.isEmpty(student.getName())) {
           // Here, you can also use root.get("name").as(String.class) to strongly convert generic types.
                    stuNameLike = cb.like(root.<String> get("name"), "%" + student.getName() + "%");
                }
                
                Predicate clazzNameLike = null;
                if(null != student && null != student.getClazz() && !StringUtils.isEmpty(student.getClazz().getName())) {
                    clazzNameLike = cb.like(root.<String> get("clazz").<String> get("name"), "%" + student.getClazz().getName() + "%");
                }
                
                if(null != stuNameLike) query.where(stuNameLike);
                if(null != clazzNameLike) query.where(clazzNameLike);
                return null;
            }
        }, new PageRequest(page.getPage() - 1, page.getLimit(), new Sort(Direction.DESC, page.getSortName())));
    }
}

Posted by skymanj on Tue, 14 May 2019 07:19:20 -0700