版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_21443203/article/details/89353370
SpringData JPA
springdata 学习日志–day1
1.Spring-data-jpa的基本介绍
- spring-data jpa表示与jpa的整合,hibernate实现标准由jpa提供(接口)。
- 在原生的hibernate中操作数据库的对象为Session,在JPA中叫EntityManager,在MyBatis中叫SqlSession;
- 在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.用法与细节
- XXXRepositoryImpl不需要实现XXXRepository接口,因为后者继承了JpaRepository如果我们的UserRepositoryImpl实现了UserRepository接口,导致的后果就是我们势必需要重写里面的所有方法,这是Java语法的规定,如此一来,悲剧就产生了,UserRepositoryImpl里面我们有很多的@Override方法,这显然是不行的,结论就是,这里我们不用去写implements部分。
- 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())));
}
}