欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JPA学习

程序员文章站 2022-03-02 15:23:13
...

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 >

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

<!-- 属性资源 -->
<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

相关标签: jpa