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 >

<?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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值