springdata 学习日志

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_21443203/article/details/89353370

springdata 学习日志–day1

1.Spring-data-jpa的基本介绍

  1. spring-data jpa表示与jpa的整合,hibernate实现标准由jpa提供(接口)。
  2. 在原生的hibernate中操作数据库的对象为Session,在JPA中叫EntityManager,在MyBatis中叫SqlSession;
  3. 在ORM框架中,都会提供基本的CRUD功能,如果用原生的框架,一般业务逻辑代码会自定义,自己编写sql语句,而spring-data jpa的强大之处就是几乎可以不需要写一条sql,实现对复杂逻辑的业务sql实现。

2.与Spring的整合

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

<!-- 数据库连接 -->
<context:property-placeholder location="classpath:your-config.properties" ignore-unresolvable="true" />
<!-- service包 -->
<context:component-scan base-package="your service package" />
<!-- 使用cglib进行动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- 支持注解方式声明式事务 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<!--base-package表示dao接口位置,repository-impl-postfix属性代表接口的实现类的后缀结尾字符,spring-data-jpa的习惯是接口和实现类都需要放在同一个包里面,UserRepositoryImpl这个类的定义的时候我们不需要去指定实现UserRepository接口,根据spring-data-jpa自动就能判断二者的关系-->

<jpa:repositories base-package="your dao package" repository-impl-postfix="Impl" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager" />
<!-- 实体管理器 -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <!--加载实体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>

<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- 数据源 -->
<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>

<!-- 事务 -->
<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>
<!-- 事务入口 -->
<aop:config>
    <aop:pointcut id="allServiceMethod" expression="execution(* your service implements package.*.*(..))" />
    <aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice" />
</aop:config>

`

3.用法与细节

  1. XXXRepositoryImpl不需要实现XXXRepository接口,因为后者继承了JpaRepository如果我们的UserRepositoryImpl实现了UserRepository接口,导致的后果就是我们势必需要重写里面的所有方法,这是Java语法的规定,如此一来,悲剧就产生了,UserRepositoryImpl里面我们有很多的@Override方法,这显然是不行的,结论就是,这里我们不用去写implements部分。
  2. for instance:
第一步-建表
第二步-实体类
@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
}
第三步-写接口
public interface UserRepository extends JpaRepository<User, Integer>{}
至此User的基础CRUD就ok了。

测试》:

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.SpringData方法命名规范和原理

在UserRepository接口中定义:
	User findByNameAndPassword(String name, String password);
被翻译成的sql语句:
	select * from user where name = ? and password = ?;

原理是:spring-data-jpa会根据方法的名字来自动生成sql语句,我们只需要按照方法定义的规则即可,上面的方法findByNameAndPassword,spring-data-jpa规定:
方法都以findBy开头,sql的where部分就是NameAndPassword,在属性后面加关键字如 like就可以模糊查询,如User findByNameLike(String name);生成的sql就是select * from user where name like = ?

4.动态查询与分页等
 a.使用JPQL,类似Hibernate的HQL
  前面说到了在UserRepository接口的同一个包下面建立一个普通类UserRepositoryImpl来表示该类的实现类,同时前面也介绍了完全不需要这个类的存在,但是如果使用JPQL的方式就必须要有这个类。

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.使用JPA的动态接口,以类型检查的方式,拼接sql

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;//where后面的参数对象
                if(null != student && !StringUtils.isEmpty(student.getName())) {
           // 这里也可以root.get("name").as(String.class)这种方式来强转泛型类型
                    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())));
    }
}

猜你喜欢

转载自blog.csdn.net/qq_21443203/article/details/89353370