1.什么是spring data jpa?
是一种基于jpa进行的再次封装的框架,其底层原理还是由其他框架实现的(这里用的是hibernate)
2.配置的过程
(1)创建一个maven工程,在pom文件中导入相应的坐标。
单元测试 junit 4.9
Aspectjweaver 支持切入点表达式和aop相关注解
Spring相关 版本都是4.2.4.RELEASE
Spring-aop aop切面编程的支持包
Spring-test 单元测试和集成测试的简单封装
Spring-context Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等
Spring-context-support 拓展支持,用于MVC方面
Spring-beans spring ioc的基础实现
Spring-core spring核心组件
Spring-orm 整合第三方的orm框架
Hibernate相关 版本 5.0.7.Final
Hibernate-core hibernate核心包
Hibernate-entitymanager 实体管理包(和jpa整合)
Hibernate-validator 参数校验
C3p0 0.9.1.2 连接池
Log4j 1.2.12 日志
Slf4j-log4j12 1.6.6
Mysql-connector-java 5.1.6 数据库
Spring-data-jpa 1.9.0.RELEASE spring-data-jpa 核心包
Javax.el-api 2.2.4 必须导入的包
Javax.el 2.2.4
(2)在applicationContext中编写对应的配置文件。
1.配置数据源
<context:property-placeholder location="classpath:jdbc.properties"/><!-- 定义引用的文件,这样写容易改动-->
<context:component-scan base-package="com.cn"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- c3p0数据源-->
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="driverClass" value="${jdbc.driver}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
2.配置实体管理工厂bean
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
//配置数据源
<property name="dataSource" ref="dataSource"/>
//指定扫描实体类的包
<property name="packagesToScan" value="com.cn.entity"/>
//配置持续化提供者
<property name="persistenceProvider">
//使用的是hibernate
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
//配置jpa适配器
</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.MySQLDialect"/>
//是否显示sql语句
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaProperties">
<props>
//配置在更新时,是否创建表,创建表是否删除之前表的内容
<prop
key="hibernate.hbm2dd1.auto">update</prop>
</props>
</property>
</bean>
3.配置事务和jpa的相关配置。
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
//jpa:repositories jpa仓库 需要指定dao放置的位置 base-package
<jpa:repositories base-package="com.cn.dao" transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory"/>
(3)创建实体类
将注解映射到数据库表中,配置和jpa配置相同
(4)编写实体类的dao接口
需要继承两个接口JpaRepository<T,ID>和JpaSpecificationExecutor
T 代表实体类 ID代表 实体类的主键
public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer>
1.JpaRepository<T,ID>提供了一些简单的数据库操作方法
FindOne 通过主键查询单个
Sava 保存,如果有主键就更新,没有就添加
Delete 通过主键删除
FindAll 查询所有
2.复杂的操作有多种方式进行查询
- JPQL查询(查询需要加上Query注解,修改还需要加上Modifying注解)
//查询
@Query(value = "from Customer where custName= ? ")
Customer findByName(String name);
//更新,1代表第一个参数,2代表第二个参数,表示方法定义的时候两个参数的顺序
@Query(value = "update Customer set custName=?1 where custId=?2")
@Modifying
void update(String custName,long custId);
调用更新方法的时候,因为需要对数据库内容进行修改,所以需要配置事务注解
@Transactional
@Rollback(value = false)
- 使用sql语句
//查询
@Query(value = "select * from cst_customer",nativeQuery = true)
public List<Customer> findBySql();
//更新
@Query(value = "update cst_customer set cust_name=? where cust_id=?",nativeQuery = true)
@Modifying
void updatesql(String custName,long custId);
使用sql语句,只需要在@Query注解上面加上nativeQuery = true就可以了,其余和jsql的方式一样
3.使用方法查询,由jpa内部自动生成sql语句进行创建
方法查询的规范
find+全局修饰+By+实体属性名称+限定词+连接词+(其他实体属性)+OrderBy+排序属性+排序方向
如:findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(String firstName,String lastName)
4.使用Spring data jpa 中JpaSpecificationExecutor接口
我们要使用其中的方法就必须了解Specification接口 它定义了一个方法toPredicate 其中 有三个参数Root (代表想要查询表的实体类) CriteriaQuery 顶层查询 CriteriaBuilder 具体查询标准
①相关查询
精确查询: cb.equla(root.get(“custName”),”哈哈”);
并列查询:
cb.equla(root.get(“custName”),”哈哈”);
cb.equla(root.get(“custId”),”1”);
cb.and(p1,p2);
模糊查询:
cb.like(root.get(“custName”).as(String.class),”哈%”);
排序查询:
排序查询只需要创建一个排序对象
Sort sort=new Sort(Sort.Direction.DESC,”custName”);第一个参数代表排序方式,第二个表示通过哪个属性排序
分页查询:
分页查询需要一个Pageable对象这个 声明该对象 Pageable pageable=new PageRequest(0,3) 第一个参数从哪开始 第二个参数 一页有几个数据
然后通过customerDao接口调用方法 返回一个分页对象 这个对象是spring data jpa 所提供的 里面包含分页需要的所有属性
totalElements获总数据数量 totalPages 获得一页有几个数据
content 表示 返回的内容
//一般查询
Specification<Customer> spec=new Specification<Customer>(){
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//root就是 相当于实体类对象 query 自定义查询 cb:构建查询
return cb.like(root.get("custName").as(String.class),"7%");
}
};
List<Customer> all = customerDao.findAll(spec);
//排序查询
customerDao.findAll(new Sort(Sort.Direction.DESC,"custName")
//分页查询
Pageable pageable=new PageRequest(0,3);
Page<Customer> customers = customerDao.findAll(pageable);
System.out.println(customers.getTotalElements());
System.out.println(customers.getTotalPages());
System.out.println(customers.getContent());
3.关于一对多和多对多的操作
(1)一对多
一的一方:
/* @OneToMany(targetEntity = LinkMan.class)
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")*/
@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)
private Set<LinkMan> linkmans=new HashSet<LinkMan>();
多的一方:
@ManyToOne(targetEntity = Customer.class,fetch =FetchType.LAZY )
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Customer customer;
① 主要区别在于 在实体类中 要和 其他类有关系
操作在于
1的一方需要有一个存储多的一方的集合,并且需要加上注释@OneToMany(mappedBy=”customer”,cascade=Cascade.Type.ALL)
其中mappedBy 表示放弃维护权,第二个代表级联操作:操作一个对象同时操作它的关联对象
为何要放弃维护权?
因为多对一方再保存的时候已经保存了外键信息,所以不需要再进行更新了
多的一方需要添加一个一的一方的对象同时需要加上注释
@ManyToOne(targetEntity=Customer.class,fetch=FetchType.LAZY)
@JoinColumn(name=”lkm_cust_id”,referencedColumnName=”cust_id”)
第一个代表多对一,属性为 目标实体类 需要一方面的字节码文件,还可以配置加载方式 LAZY为懒加载,EAGER为直接加载
第二个注释中 名字为 外键名,第二个为该外键在主表的名字
② 多表操作(1对多)增删改查
Add:需要加上@Transaction和@Rollback(注释)
添加的时候 因为使用级联操作,所以只需要在主方进行保存(一方)
Delete:删除的时候,一方删除就可以了
Update:无特殊
Search:查询的时候通过对象导航进行查询,但是再toString方法中一定要删除其中一个的输出另一个类的方法,不然会无限循环,出错 同时查询要加上@Transactional注释
(2)多对多
双方:
//role方
@ManyToMany(targetEntity = User.class,cascade = CascadeType.ALL)
@JoinTable(name = "role_user",joinColumns = {
@JoinColumn(name = "ru_role_id",referencedColumnName = "role_id")
},inverseJoinColumns = {
@JoinColumn(name = "ru_user_id",referencedColumnName = "user_id")
})
private Set<User> users=new HashSet<User>();
---------------------------------------------
//user方
@ManyToMany(mappedBy = "users")
private Set<Role> roles=new HashSet<Role>();
①配置相关说明
建议多对多的时候也是 一个负责 维护 一个放弃
需要在两个类中各加入一个对方的集合
在集合上面进行配置
主 类 @ManyToMany(targetEntity=User.class,cascade=CascadeType.ALL)
@JoinTable(name=”role_user”,joinColumns={
@JoinColumn(name=”ru_role_id,referencedColumnName=”role_id”)
},inverseJoinColumns={@JoinColumn(name=”ru_user_id”,referencedColumnName=”user_id”)}
)
其中JoinTable为中间表
joinColumns 中 name为中间表中的主外键名 referencedColumnName为 主表中名
inverseJoinColumns中第一个为中间表中另一个表的外键名 referencedColumnName为 另一个表中的主表外键名
第二个类只需要在集合方法上加上@ManyToMany(mappedBy=”users”)
② 多表操作增删改查
增加:主类操作
删除:主类进行删除(会删除所有相关)
修改:各改各的
查:互相的都可以查,但是toString中 要删除一个 否则会报错
一方查多方:默认延迟加载,因为多方数据多
多方查一方:默认即时加载,因为一方数据只有一条