JPA学习
1.jpa
1.ORM思想
ORM(Object-Relational Mapping) 表示对象关系映射。 操作对象就是操作表, 尽量不写sql
ORM就是建立 实体类 和 数据库表 之间的关系,从而达到操作实体类就相当于操作数据库表的目的。(框架建立这样的关系,类名-表名,属性-列) 操作对象就是操作表;基于orm思想的, 能够建立了对应关系的框架;Mybaitis(半自动)/hibernate(全自动化) 参数自动映射/自动封装结果集 自动!!!
简化dao层写法,简化增删改查,不写sql语句 spring data jpa
2.JPA规范(sun)
JPA的全称是Java Persistence API, 即Java 持久化规范,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。一套规范, 接口 (类似于JDBC)
对所有的orm框架进行规范; 由实现了规范的框架来具体干活
JPA本身不是框架, 是规范, 要实现要干活, 需要实现了JPA规范的框架, 例如hibernate // 5.0.7版本的
3.入门测试
1.Maven工程,配置文件pom; 这里就是jpa(hibernate jpa),跟spring还无关!
测试Junit
日志Slf4j-Log4j
Hibernate对jpa的支持 hibernate-entitymanager 不是hibernate
数据库 mysql
Maven编译插件 1.8
2.建立实体类,在实体类上使用JPA注解的形式配置映射关系
@Entity // 作用:指定当前类是实体类。
@Table(name = “cst_customer”) // 作用:指定实体类和表之间的对应关系。
public class Customer implements Serializable{
@Id // 作用:指定当前字段是主键。
@GeneratedValue(strategy = GenerationType.IDENTITY) // 作用:指定主键的生成方式。 四中类型, strategy :指定主键生成策略。
@Column(name=“cust_id”) // 作用:指定实体类属性和数据库表之间的对应关系
3.JPA核心配置文件,在java工程的src路径下创建一个名为META-INF的文件夹,在此文件夹下创建一个名为persistence.xml的配置文件,没有使用spring整合, 没有spring的事 //jpa核心配置文件,类似mybatis核心配置文件,
<?xml version="1.0" encoding="UTF-8"?><!--配置持久化单元
name:持久化单元名称
transaction-type:事务类型 多个操作在一个数据库
RESOURCE_LOCAL:本地事务管理 多个操作在多个数据库,要么都成功,要么都失败
JTA:分布式事务管理 -->
<persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
<!--指定JPA规范的提供商 hibernate提供支持-->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
//难道没有使用连接池???用的是什么连接池
<!-- 数据库驱动 -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<!-- 数据库地址 -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/springdatajpa"/>
<!-- 数据库用户名 -->
<property name="javax.persistence.jdbc.user" value="root"/>
<!-- 数据库密码 -->
<property name="javax.persistence.jdbc.password" value="123456"/>
<!--jpa提供商的可选配置:我们的JPA规范的提供商为hibernate,
所以jpa的核心配置中兼容hibernate的配置 -->
<!--打印sql语句-->
<property name="hibernate.show_sql" value="true"/>
<!--格式化sql语句-->
<property name="hibernate.format_sql" value="true"/>
</properties>
4.test
* 创建实体管理器工厂EntityManagerFactory emf,借助Persistence的静态方法createEntityManagerFactory()来获取;
* 创建实体管理器EntityManager em;
* 事务 ,所有操作要放在事务里 获取事务,开启,提交 ; 重要!!!
* 操作 增删改查 persist
* 关闭实体管理器和工厂 em/emf
@Test
public void test1(){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myJpa");
EntityManager em = emf.createEntityManager();
EntityTransaction es = em.getTransaction();
es.begin();
Customer customer = new Customer();
customer.setCustAddress("guang拦路");
customer.setCustName("旺旺");
em.persist(customer);
es.commit();
em.close();
emf.close();
}
5.建表语句ddl
create/ 先删表再建表, 数据会丢失
create-drop/ 删,创建,最后再删
update/ 没有表就建表, 有表会根据最新的实体进行更新
Validate/ 没有表,也不更新, 有表如果不一致,还报错
6.主键策略
IDENTITY 数据库自动生成, 自动增长 //Mysql , 自增
4.JPA-API
原生api实现增删改查:
Persistence类 获取工厂对象 得到EntityManagerFactory emf
EntityManagerFactory 接口 创建em实例 线程安全/ 重量级 可以单例下使用, 唯一的工厂对象
EntityManager : em是完成持久化操作的核心对象。实体类作为普通 java对象,只有在调用 EntityManager将其持久化后才会变成持久化对象。操作实体
getTransaction : 获取事务对象 ; EntityTransaction是完成事务操作的核心对象; 一切在事务内完成
操作的都是实体,
增删改: em.persist /em.merge /em.remove /em.find
persist : 保存操作; id如果存在会报错,只能insert不能update
merge : 1. 更新操作 (new对象,merge; 会先查id,存在就更新update,不存在就保存insert)
2. 也可以先查出来, 直接重新set值就可以了(仍然两次sql, 仍然要先查,只是确定是更新) // 查到的如果不存在去硬set会报错 null异常
remove : 删除操作 只能先查再删除 如果new一个对象然后remove会报错,//因为,可能是不存在的,此时不可删
查: em.find
find/getReference : 根据id查询 主键
Customer customer = em.find(Customer.class, 1L); Customer customer = em.getReference(Customer.class,1L);
5.JPQL实现复杂查询
查询!!! 实现的是查询!!! 可以实现复杂查询 select
持久化查询语言 java persisent query language
面向对象,通过类名和属性 不是表和列了
记住: 通过em, 创建查询对象 Query + 并且写jpql语句 em.createQuery(“写jpql语句”)
不能select * ; 不能部分字段(部分字段无法与要映射的实体相匹配,多也不行,少也不行),默认就是select所有字段from 实体 (也就是是实体对应的表,这张表包含字段大于等于这个实体) , 返回的也就是相应实体对象,不需要写XXX.class了
与写sql相区别,nativesql更灵活,只需要塞满返回的那个实体就好,多查没关系,不能少; 没有实体与表之间的映射关系了,这时候不是orm,而就是sql,从表里查字段;
查询全部
//创建查询对象,写的是JPQL语句
Query query = em.createQuery(“from Customer”);
List list = query.getResultList();
分页查询
Query query = em.createQuery(“from Customer”);
query.setFirstResult(0);
query.setMaxResults(2);
List list = query.getResultList();
条件查询 条件写在jpql里 再setparameter(),设置条件值
//创建查询对象,写的是JPQL语句
Query query = em.createQuery(“from Customer where custName like ?”);
//给占位符设置值
query.setParameter(1,"%张三%");
List list = query.getResultList();
排序查询 排序规则直接写在jpql里
//创建查询对象,写的是JPQL语句
Query query = em.createQuery(“from Customer order by custId desc”);
List list = query.getResultList();
统计查询
Query query = em.createQuery(“select count(*) from Customer ”);
Query.getSingleResult(); //已经明确有一个结果了; 这样写,如果结果是null,一条都没有,查不到,就报错
==============
*** 可以写sql语句*** 写的是表名和列名
Query query = em.createNativeQuery(“select * from cst_customer”,Customer.class);
List list = query.getResultList();
写的是sql语句,直接查的是表(不是通过实体映射了),所以查的字段个数随便了,但要能满足,返回要封装的类实体 //对于要映射的实体来说,可以多,但不能少
使用这个比较多, 就按以前的sql那样写
2.Springdatajpa
6.Springdatajpa介绍
Spring data 的产品 , 简化jpa的操作 jpa应用框架
是对JPA的封装,仍是规范, 把jpa(hibernate jpa)交给spring管理, spring整合jpa 在jpa基础上做了层封装
三层中的DAO层!!!
Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现, 动态代理
推荐使用Spring Data JPA + ORM(如:hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦
原理:
spring data jpa 底层的api仍是jpa, 只是进行了封装, 通过代理对象进行这些jpa的api的调用(persist/remove/merge/find)
Dao层是接口, 不是类, 也不需要实现类了就可以直接用, dao接口不需要写实现类(dao接口继承了…repository接口 使用继承的api)
Jdbc-hibernate-jpa-springjpa = dao层
Spring data jpa环境依赖和配置文件
Spring: (context和aspect和orm包)
spring data jpa
hibernate(核心包core和对jpa的支持包entitymanager) 此外要有数据源德鲁伊或者光,也就是连接池
数据库驱动mysql
el(使用spring data jpa需要, 必须引入)
Test和logo (其他支持包)
写核心配置文件 applicationContext.xml //spring对jpa进行整合
<?xml version="1.0" encoding="UTF-8"?><bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3380/springjpa"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--把EntityManagerFactory交给spring管理-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
<!--扫描实体类所在的包-->
<property name="packagesToScan" value="com.ris.entity"/>
<!--JPA提供商-->
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true"/>
<property name="database" value="MYSQL"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- 整合spring data jpa-->
<jpa:repositories base-package="com.ris.dao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"/>
Dao层接口的写法 ,继承接口, 使用继承的接口的方法即可!!!
7.Springdatajpa API
(1)使用接口自带的api
CRUD 操作的都是实体对象
保存/更新, save() 调用save()这个方法,就意味着先select然后insert或者updtae
1.new好一个对象, 然后save() ; 会先查select,主键id存在就是更新update 否则是新增insert, 两次sql 先select, 再insert或者update
2.所以如果确定是更新操作,说明id一定存在(该条数据), 所以建议做更新的时候,先查出来, 然后直接set值去做更新, !!!更新
【这时候set值,会执行save(),但是确定性就是更新了,仍然是两次sql,一次select,第二次确定就是update】
查询, findById(),
返回optional , 所以后面. orElse();
删除, delete()
直接根据id删对象, deleteById/ 其实是先查再删(要先查出来确定有这个对象)
先查出来对象, 确定有这个对象, 再删对象 delete delete删对象本身也又还是先查再删 ,
查询
除了findByid
还有其他几个:
查询所有 findAll
排序查 指定规则,作为参数放在查询里 findAll(sort); 分页查 findAll(pageable)
Sort sort = new Sort(Sort.Direction.DESC,“custId”); List list = customerDao.findAll(sort);
Pageable是分页条件, 是一个接口, 不能直接new, 通过PageRequest来实现 PageRequest.of();得到的是Page<>对象,分页结果对象
统计记录数 count
是否存在 existById
(2)自己在dao接口写方法,使用jpql
上面都是dao接口自带的api,可以直接用,也不需要写实现;
但是如果想实现更灵活的查询条件,可以使用jpql语句,自己写方法
加@query注解,写语句; 查询所有/条件查询
@Query(“from Customer”)
List findAllCustomer();
@Query(“from Customer where custName = ?1”)
Customer findCustomerByCustName(String custName);
@Query(“from Customer where custId = ?2 and custName = ?1”)
Customer findCustomerByCustIdAndCustName(String custName,Long custId);
也可以做更新和删除,在@query注解基础上加@modifying注解
@Query(“update Customer set custName = ?2 where custId = ?1”)
@Modifying
void updateCustomer(Long custId,String custName);
(3)自己在dao接口写方法,使用sql
@Query(value=“select * from cst_customer where cust_name like ?1”,nativeQuery = true)
List findAllCustomerSql(String custName);
(4)方法命名规则
只能是查询 findBy? 就是在构造查询条件而已
按照一定规则去命名方法,方法上不用加注解了
查询方法以findBy开头; 条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。
//方法命名方式查询(根据客户名称查询客户)
public Customer findByCustName(String custName); 写的是类名和属性名
在CustomerDao中添加findByCustName方法,表示根据cust_name来查询,默认是=查询
在CustomerDao中添加findByCustNameLike方法,相当于where cust_name like ?
在CustomerDao中添加findByCustNameLikeAndCustIndustry方法,相当于where cust_name like ? and cust_industry=?,形参的顺序不能乱。
在CustomerDao中添加findByCustNameLikeAndCustIndustryIsNull方法,相当于where cust_name like ? and cust_industry is null
在CustomerDao中添加findByCustNameLikeOrCustIndustryIsNot方法,相当于where cust_name like ? or cust_industry != ?
以上,更新和删除操作,一定要加事务,因为有两次sql操作,一次查询然后再更新或者/删除;
8.Specifications动态查询
在Spring Data JPA中,对于定义符合规范的Dao层接口,我们只需要遵循以下几点就可以了:
/**
- JpaRepository<实体类类型,主键类型>:用来完成基本的CRUD操作
- JpaSpecificationExecutor<实体类类型>:用于复杂查询(分页等查询操作)
*/
public interface CustomerDao extends JpaRepository<Customer,Long>,JpaSpecificationExecutor{
}
这些方法参数都有specification这个接口,需要传入接口实现类对象,其实就是在构造查询条件;
=============JPA
一、基本
9.内容大纲
基本:Spring整合hibernate
关键:Spring整合hibernate基于jpa规范 (spring整合hibernate(jpa))
重点:Spring data jpa (spring data 整合jpa)
补充:Spring data redis
10.环境版本
JDK1.7
Hibernate 5.0.7final
Spring 4.2.0release
Spring data jpa 1.9.0release
Spring data redis 1.6.0release
11.技术
Hibernate:
全自动的持久层框架,操作数据库,实现crud
Jpa:
规范,标准,不是具体的技术,sun公司制定
Hibernate jpa:
hibernate在3.2版本之后,提供了基于jpa规范的实现
Spring data:
spring.io官网介绍,平台,提供了操作数据的模块
Spring data jpa:
spring data下面具体的技术,spring对jpa的封装和增强,默认使用的是hibernate来实现jpa
- Spring data redis:
spring data 下面的技术,操作redis
二、Spring整合hibernate
12.导依赖
普通工程,不是web工程,也不是maven工程; 需要lib目录(不是在src下面,而是与src平级的目录)存放第三方jar包
spring : ioc的包/aop的包/jdbc的包/orm/test/apache-logging 【spring整合一切,整合其他框架】整合orm框架,整合junit
Hibernate: 9个包
Mysql
C3p0
Junit (直接buildpath-add library- junit4)
//如果是maven工程就在pom.xml文件进行导包
13.Spring核心配置文件
applicationContext.xml,注意命名空间,约束,放在src目录下 (源码和配置文件都是在src目录下,pom.xml配置文件与src平级)
配值 读取properties文件
<context:property-placeholder location= “classpath:”> classpath就是src目录的意思
配c3p0连接池
<bean id=”dataSource” class= > 注入数据库连接信息
配置hibernate的sessionFactory (也就是spring整合hibernate)
<bean id=”sessionFactory ” class=”” > 注入 dataSource, hibernateProperties, packagesToScan(扫描实体所在包)
配置hibernate的事务管理器
注入sessionFactory
配置 开启注解对事务的支持
<tx:annotation-driven >
配置 开启springioc的注解扫描
<context: compentScan >
<!-- 属性资源 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.panda.pojo</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="cn.panda"></context:component-scan>
14.测试,通过hibernate进行crud
实体类@Entity @Table @Column
Dao接口/或者直接写dao类, 写方法, hibernateTemplate配置到bean/或者直接继承此 spring整合后提供的操作对象
@Repository
public class CusDao extends HibernateDaoSupport {
//spring整合hibernate后,提供了操作hibernateTemplate的模板,hibernateTemplate需要注入sessionFactory
@Resource
public void setSessionFactory0(SessionFactory sessionFactory){
super.setSessionFactory(sessionFactory);
}
//private HibernateTemplate hibernateTemplate = this.getHibernateTemplate();
public HibernateTemplate getHHH(){
return this.getHibernateTemplate();
}
public void saveCus(Customer cus){
// super.setSessionFactory(sessionFactory);
// this.getHibernateTemplate().save(cus);
// HibernateTemplate hhh = new HibernateTemplate(sessionFactory);
// hhh.save(cus);
//this.getHibernateTemplate().save(cus);
getHHH().save(cus);
}
public void deleteCus(Customer customer){
getHHH().delete(customer);
}
public void updateCus(Customer customer){
getHHH().update(customer);
}
public Customer queryCus(Long id){
return getHHH().get(Customer.class, id);
}
}
测试类 对dao接口实现类方法进行测试 crud 这里如果不使用dao层,也可以直接操作hibernateTemplate进行crud
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
public class TestDemo {
@Autowired
private CusDao cusDao;
@Test
@Transactional
@Rollback(value=false)
public void testName() throws Exception {
Customer cus = new Customer();
cus.setCustId(18L);
cus.setCustAddress("更新地址1.26");
cus.setCustName("豆瓣小");
//cusDao.saveCus(cus);
//cusDao.updateCus(cus);
//cusDao.deleteCus(cus);
Customer queryCus = cusDao.queryCus(1L);
System.out.println(queryCus);
}
}
其他查询方式(上面只能通过主键) 要先拿session
HQL查询语言,类似JPQL
SQL查询,本地sql,类似nativeQuery
//两种获取session的方式,opensession和currenetsession
Session session = hibernateTemplate.getSessionFactory().getCurrentSession();
Query sqlquery = session.createSQLQuery("select * from cst_customer where cust_name = ?").addEntity(Customer.class).setString(0, "鲁智深");
List list2 = sqlquery.list();
System.out.println(list2.get(0).toString());
Query query = session.createQuery("from Customer where custName = :custname").setString("custname", "张无忌"); //不能写投影 select,写了反而无法映射到结果集了
List<Customer> list = query.list();
String string = list.get(0).toString();
System.out.println(string);
QBC查询,query by criteria,彻底放弃sql语言的写法,用对象和方法去操作数据库
//两种获取session的方式,opensession和currenetsession
Session session = hibernateTemplate.getSessionFactory().getCurrentSession();
Criteria c = session.createCriteria(Customer.class); //select * from cst_customer where
c.add(Restrictions.eq("custName", "张无忌"));
List list = c.list();
System.out.println(list.get(0).toString());
测试问题描述:“
1.Mysql版本的问题
”
2.Dao层直接 extends HibernateDaoSupport ,hibernateTempalte需要sessionFactory才能使用
Caused by: java.lang.IllegalArgumentException: ‘sessionFactory’ or ‘hibernateTemplate’ is required
这样写不对 ???
@Autowired
private SessionFactory sessionFactory;
public void saveCus(Customer cus){
createHibernateTemplate(sessionFactory).save(cus);
// HibernateTemplate = new hibernateTemplate(sessionFactory); 也不对
解决:
@Resource
public void setSessionFactory0(SessionFactory sessionFactory){
super.setSessionFactory(sessionFactory);
}
@Autowired 是说Spring自动注入 ,可以用到法方上,属性上,构造器上。 只要这三个地方用上这个注解,spring容器会自动把需要的对象给你注入进去。当然如果spring查找不到对于得bean就会报错的。
3.hibernateTemplate为空
private HibernateTemplate hibernateTemplate = this.getHibernateTemplate();
作为成员变量直接写在类里,然后在方法里使用,hibernateTemplate会报null ???
需要在方法里去获取并使用才可以
三、Spring整合jpa
【Hibernagte3.2提供了jpa标准的实现】
Jpa是标准,没有实现 + Hibernate是持久层框架,orm
Hibernate jpa 是hibernate对jpa的实现,就是学习jpa的时候的那个原生jpa
因此对hibernate的使用有两种方式了,原生的,jpa标准的
创建项目
15.导依赖
导jar包, 加一个hibernate-entitymanager
org.hibernate
hibernate-entitymanager
${hibernate.version}
16.配置文件
sessionfactory是原生hibernate的,改成基于jpa的,所以配置entitymanagerfactory
换工厂 jpa的 emf
换事务管理器 jpa的
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database" value="MYSQL" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="packagesToScan">
<list>
<value>com.panda.pojo</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
17.测试
注入em,但并没有配置过em,而是要通过emf获取,emf是配置了的,加个注解
Api有所不同
@PersistenceContext(name=“entityManagerFactory”)
private EntityManager em;
@Test
@Transactional
@Rollback(value=false)
public void test3(){
Customer cus = new Customer();
cus.setCustId(1L);
cus.setCustAddress("梁山伯12");
cus.setCustName("鸠摩智12");
//em.persist(cus);
//em.merge(cus); 更新,先查,再确定是更新还是新增
//Customer cusRes = em.find(Customer.class, 2L); //查询
//em.remove(cusRes); //先查再删,在查询的基础之上再进行
实现复杂查询的几种查询方式
HQL 即JPQL
Query query = em.createQuery(“from Customer where custId > ?”).setParameter(1, 1L);
SQL 本地sql
Query nativeQuery = em.createNativeQuery(“select * from cst_customer where cust_name like :name”, Customer.class).setParameter(“name”, “鸠摩智%”);
QBC 不用sql ,
//cb: 通过cb来创建cQuery,并且构建查询条件
CriteriaBuilder cb = em.getCriteriaBuilder();
//cQuery: 是执行查询的对象 select * from 表 where
CriteriaQuery<Customer> cQuery = cb.createQuery(Customer.class);
//获取要查询的实体类对象 从这个对象里取属性作为查询的条件
Root<Customer> root = cQuery.from(Customer.class);
//构造查询条件,可以连续构造条件
Predicate cate = cb.equal(root.get("custName"),"鸠摩智"); //条件是哪个属性(在哪个实体); 值是多少
cQuery.where(cate);
//执行查询
TypedQuery<Customer> typedQuery = em.createQuery(cQuery);
List<Customer> cs = typedQuery.getResultList();
for (Customer customer : cs) {
System.out.println(customer);
}
问题
1.之前的bean配置被注掉了,xml配置文件中,影响到类中的自动装配,启动和运行工程时会报错(因为会注解扫描)
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘cusDao’: Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.hibernate.SessionFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
@Resource
public void setSessionFactory0(SessionFactory sessionFactory){
super.setSessionFactory(sessionFactory);
}
Caused by: java.lang.IllegalArgumentException: ‘sessionFactory’ or ‘hibernateTemplate’ is required
public HibernateTemplate getHHH(){
return this.getHibernateTemplate();
}
开启了自动扫描,会注入bean
解决:修改自动扫描的范围,不扫这个dao
2.关于获取emf
最原生jpa,没有交给spring进行整合,通过persistence,默认单元unit,获取emf,然后em操作,而且要手动获取事务对象,进行事务的开启关闭
EntityManagerFactory emf = Persistence.createEntityManagerFactory(“myJpa”);
EntityManager em = emf.createEntityManager();
EntityTransaction es = em.getTransaction();
es.begin();
Query query = em.createQuery("from Cus2 ");
es.commit();
em.close();
emf.close();
Spring整合了jpa后,配置文件中有emf这个bean,(没有em这个bean),直接通过注解emf->em,不用获取事务对象了,需要时自己加注解(查询不要,其他都要)
@PersistenceContext(name=“entityManagerFactory”)
private EntityManager em;
@Test
@Transactional
@Rollback(value=false)
public void test2(){
//行不通
// EntityManagerFactory emf = Persistence.createEntityManagerFactory(“entityManagerFactory”);
// EntityManager em = emf.createEntityManager();
Customer customer = new Customer();
customer.setCustName("华华123");
em.persist(customer);
}
下面这样,有bug,查询没问题,增删改不行
@Autowired
private EntityManagerFactory entityManagerFactory;
@Test
@Transactional
@Rollback(value=false)
public void test2(){
EntityManager em = entityManagerFactory.createEntityManager();
Customer customer = new Customer();
customer.setCustId(1L);
customer.setCustName("jack1231");
customer.setCustAddress("shenjiang");
em.merge(customer);
/*Customer c = em.find(Customer.class, 1L);
System.out.println(c);*/
System.out.println("ok");
}
Spring data 整合 jpa 后,一般用dao, 直接使用接口的api去操作了,但如果仍需要使用原生jpa,也还是要通过emf来拿到em;
四、Spring data jpa
Spring data的模块,基于jap,也就是用hibernate jpa实现的, 主要是简化jpa的操作,不写dao了,继承接口,直接用api
18.导包
Spring data jpa
Spring data common
org.springframework.data
spring-data-jpa
${springdatajpa.version}
<!-- el 使用spring data jpa 必须引入 -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
19.配置文件
Spring整合jpa的部分基本上保留,
命名空间,jpa
加一个 spring data jpa的配置就行了 扫描dao接口所在的包 //跟mybaitis的动态mapper接口很相似
<jpa:repositories base-package="com.ris.dao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"/>
20.实现原理
写个dao,继承jpaRepository,不用写实现了,接口提供了对数据库的操作
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor
对继承的方法的返回值做适配
实现的是分页和排序查询
增删改查
只是一个标识 实现:基于方法命名规则查询,基于@query注解查询
原理
动态代理,dao接口打印出来,是代理对象,也就是接口的实现类对象,通过jpaRepositiryFactory获取的
21.测试(四个接口)
1.直接只继承Repository,没有方法可继承,只能自己写,两种
基于方法命名规则查询
基于@query注解查询 JPQL和sql
public Customer findByCustName(); 参数如果有多个,顺序怎么
@Query("from Customer where custName = ?1")
public List<Customer> findCustmoerByJPQL(String name);
@Query(value="select * from cst_customer where cust_name like ?1" , nativeQuery=true)
public List<Customer> findCustmoerByNativeSql(String name);
如果是更新,加@modifying, 此外,不是查询的操作,增删改,在使用这个自己写的方法的时候,需要加事务注解; 继承的方法都加过了
2.crudRepository 可使用其API
增save()
更新也是save(), 所以最好是先查出来,然后直接set就可以了, 不用save()了,会自动执行save(),但要开启事务
3.pageAndSortingRepository 实现分页和排序
问题
1.Initialization of bean failed; nested exception is java.lang.AbstractMethodError
版本冲突,降低 spring-data-jpa 的版本 1.11.9.RELEASE
上一篇: 异常