zoukankan      html  css  js  c++  java
  • jpa/springdata(1)jpa

    1.什么是jpa

    假如学过hibernate在jpa会发现非常的简单,因为是同一个人写的,jpa是第三方orm框架的一种规范,hibernate作为jpa 的一个子集

    2.需要导入的jar

    这里使用的是hibernate作为orm

     待续重写整个部分

    3.jpa的配置简要说明

    新建--jpa项目(自动生成jpa项目的xml文件)

    persistence.xml,文件的名称是固定的,然后是根据name="jpa"创建EntityManagerFactory,这个类似于c3p0连接池

    <persistence-unit name="jpa" transaction-type="RESOURCE_LOCAL">
    		<!--  
    		实际上配置的是  javax.persistence.spi.PersistenceProvider 接口的实现类, 若 JPA 项目中只有一个 JPA 的实现产品, 则也可以不配置该节点. 
    		-->
    		<provider>org.hibernate.ejb.HibernatePersistence</provider>
    	
    		<!-- 添加持久化类,类似hibernate的mapper或者config.addclass()方法 -->
    		<class>com.jpa.helloworld.Item</class>	
    		<!-- 
    		配置二级缓存的策略 
    		ALL:所有的实体类都被缓存
    		NONE:所有的实体类都不被缓存. 
    		ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存
    		DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类
    		UNSPECIFIED:默认值,JPA 产品默认值将被使用
    		-->
    		<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
    	
    		<properties>
    			<!-- 连接数据库的基本信息 -->
    			<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
    			<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
    			<property name="javax.persistence.jdbc.user" value="root"/>
    			<property name="javax.persistence.jdbc.password" value="1230"/>
    			
    			<!-- 配置 JPA 实现产品的基本属性. 配置 hibernate 的基本属性,同hibernate的配置 -->
    			<property name="hibernate.format_sql" value="true"/>
    			<property name="hibernate.show_sql" value="true"/>
    			<property name="hibernate.hbm2ddl.auto" value="update"/>
    			
    			<!-- 同hibernate二级缓存配置 -->
    			<property name="hibernate.cache.use_second_level_cache" value="true"/>
    			<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
    			<property name="hibernate.cache.use_query_cache" value="true"/>
    		</properties>
    	</persistence-unit>
    

     如下配置也与hibernate类似

    public static void main(String[] args) {
    		
    		String persistenceUnitName = "jpa";//与c3p0的配置类似的加载方法
    		
    		Map<String, Object> properites = new HashMap<String, Object>();
    		properites.put("hibernate.show_sql", true);
    		
    		EntityManagerFactory entityManagerFactory = 
                  //在配置文件中配置好了直接获取
                  //Persistence.createEntityManagerFactory(persistenceUnitName);
              //在put中放置需要设置的属性,假如在xml中已经配置,那么将覆盖xml中的属性
              Persistence.createEntityManagerFactory(persistenceUnitName, properites);				
              EntityManager entityManager = entityManagerFactory.createEntityManager();
              EntityTransaction transaction = entityManager.getTransaction();
              transaction.begin();//开始事务
              transaction.commit();//提交事物	
              entityManager.close();
              entityManagerFactory.close();
    	}                    
    

     4.注解

    @Table(name="JPA_ORDERS")//对应的表名
    @Entity//标注为实体类
    public class Dept {
        private Integer id;
        private String deptName;
    
        @GeneratedValue/*获取主键的方式,主键id的描述,在hibernate中,以及mybatis中的resultmap的都是描述为id标签,
    这里获取主键的方式有IDENTITY:采用数据库 ID自增长的方式来自增主键段,Oracle 不支持这种方式;AUTO: JPA自动选择合适的策略,
    是默认选项(因为是默认的选项所以也可以不写);SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql
    不支持这种方式,TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。@GeneratedValue(strategy=GenerationType.AUTO), GenerationType.TABLE有些特殊但是避免了数据库切换不兼容的问题     @TableGenerator(name="ID_GENERATOR", //与generator="ID_GENERATOR"的值一致     table="jpa_id_generators", //数据库表的名称,这里是三列,id,PK_NAME,PK_VALUE     pkColumnName="PK_NAME",//数据库表的对应的列的名称     pkColumnValue="CUSTOMER_ID",//向对应列的名称的值     valueColumnName="PK_VALUE",//数据库表的对应的列的名称     allocationSize=100)//这里设置的值,PK_VALUE设置为100,每次id自增100     @GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR") */ @Id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="DEPT_NAME")/*对应数据库的名称,也是新建数据库的名称,假如数据库的名称与属性的名称一致,那么这类的注解也可以默认不写,
      在所有的默认的get方法上会默认的添加@Basic注解,假如在没有set方法的前提下会报错,假如现在有一个get方法,但是不需要与数据库相关联,
      那么在get方法上使用@Transient,jap处理注解在类方法上的注解,其余都在get方法上,Column还具有以下一些属性 ,unique(唯一) 、
      nullable(不能为null) 、length (长度)等, @Column(name="LAST_NAME",length=50,nullable=false)*/ public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } @Transient public void getInfo() { System.out.println(111); } }

     其他注解

     @Temporal  //时间匹配的格式

    例如

    @Temporal(TemporalType.DATE)//可选TemporalType.TIME,TemporalType.DATE,TemporalType.TIMESTAMP
    public java.util.Date getDate() {
    	return date;
    } 

    5.常用api

    1)EntityManagerFactory的常用方法

    createEntityManager():用于创建实体管理器对象实例。

    createEntityManager(Map map):用于创建实体管理器对象实例的重载方法,Map 参数用于提供 EntityManager 的属性。

    isOpen():检查 EntityManagerFactory 是否处于打开状态。实体管理器工厂创建后一直处于打开状态,除非调用close()方法将其关闭。

    close():关闭 EntityManagerFactory 。 EntityManagerFactory 关闭后将释放所有资源,isOpen()方法测试将返回 false,其它方法将不能调用,否则将导致IllegalStateException异常。

    2)EntityManager的常用方法

    1> find方法(同hibernate的get方法,用法基本一致)

    Department dept = entityManager.find(Department.class, 1);//1表示更具id查询的

    2> getReference方法(类似于hibernate的load方法,用法基本一致,延时加载,使用代理类)

    3> persist方法(类似hibernate的persist方法,没有save方法,不能设置id)

    entityManager.persist(mgr);

    4> remove方法(类似于hibernate的delete方法)

    5> merge方法(类似于updateorsave方法,但是又不同,在updateorsave方法中的session不能同时关联两个oid,而merge的entityManager可以这么去做)

    customer.setId(4);
    Customer customer2 = entityManager.find(Customer.class, 4);
    entityManager.merge(customer);
    System.out.println(customer == customer2); //false
    

    6> flush方法(类似hibernate的flush,不会提交事务,只是一个sql语句,事务没有提交,那么数据库的数值还是没变)

    7> clear方法(类似hibernate的clear方法,清除一级缓存)

    8> contains (Object entity) 方法 (判断entity实例是否属于当前持久上下文环境管理)

    9> isOpen方法(判断实体管理器是否处于打开状态)

    10> getTransaction方法(获取事物)

    11> close方法(关闭)

    12>refresh方法(类似hibernate的refresh方法,将持久化刷新到缓存)

    13>createQuery(String  sql) 方法(类似hibernate的createQuery方法)

    14>createNativeQuery (String sqlString)方法()使用规范的sql语句

    15>getTransaction方法(获取事物)

    3)EntityTransaction的方法

    1)begin ()用于启动一个事务,此后的多个数据库操作将作为整体被提交或撤消。若这时事务已启动则会抛出 IllegalStateException 异常。

    2)commit ()用于提交当前事务。即将事务启动以后的所有数据库更新操作持久化至数据库中。

    3)rollback ()撤消(回滚)当前事务。即撤消事务启动后的所有数据库更新操作,从而不对数据库产生影响。

    4)setRollbackOnly ()使当前事务只能被撤消。

    5)getRollbackOnly ()查看当前事务是否设置了只能撤消标志。

    6)isActive ()查看当前事务是否是活动的。如果返回true则不能调用begin方法,否则将抛出 IllegalStateException 异常;如果返回 false 则不能调用 commit、rollback、setRollbackOnly 及 getRollbackOnly 方法,否则将抛出 IllegalStateException 异常

    5.关系映射

    1)1对1

        @JoinColumn(name="MGR_ID", unique=true)//对应列,unique=true满足唯一
        @OneToOne(fetch=FetchType.LAZY)//fetch=FetchType.LAZY延迟加载,存在的异常类似hibernate的load
        public Manager getMgr() {
            return mgr;
        }//单向一对一
    
        @OneToOne(mappedBy="mgr")//mappedBy="mgr"表示维护的一端,没写默认都是对应主键的外键关联
        public Department getDept() {
            return dept;
        }//双向一对一
    

    2)单向1对多

      @JoinColumn(name="CUSTOMER_ID")
        @OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy="customer")//cascade={CascadeType.REMOVE}级联,mappedBy="customer"维护的一端
        public Set<Order> getOrders() {
            return orders;
     }

    3)单向多对1

    @JoinColumn(name="CUSTOMER_ID")
        @ManyToOne(fetch=FetchType.LAZY)
        public Customer getCustomer() {
            return customer;
        }
    

    4)双向1对多

    2)和3)一起

    5)多对多

    @ManyToMany(mappedBy="categories")
        public Set<Item> getItems() {
            return items;
       }
    
    @JoinTable(name="ITEM_CATEGORY",      //@JoinTable 来映射中间表,name 指向中间表的名字,多对多是基于外表的
                joinColumns={@JoinColumn(name="ITEM_ID", referencedColumnName="ID")},//joinColumns 映射当前类所在的表在中间表中的外键,name 指定外键列的列名,
    
    referencedColumnName 指定外键列关联当前表的哪一列,inverseJoinColumns={@JoinColumn(name="CATEGORY_ID", referencedColumnName="ID")})//inverseJoinColumns
    
    映射关联的类所在中间表的外键 
        @ManyToMany
        public Set<Category> getCategories() {
            return categories;
        }
    

    6.二级缓存

       <!--配置二级缓存的策略
            ALL:所有的实体类都被缓存
            NONE:所有的实体类都不被缓存.
            ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存
            DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类
            UNSPECIFIED:默认值,JPA 产品默认值将被使用
            -->
            <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>//基本类似hibernate,原理和hibernate和mybatis差不多,前提需要开启被管理的orm框架的二级缓存

    7.jpql和hibernate的hql的语法基本类似

    1)createQuery方法:

    public void testPartlyProperties(){
            String jpql = "SELECT new Customer(c.lastName, c.age) FROM Customer c WHERE c.id > ?";/*Customer c,根据Customer的注释可以找到表名,new Customer(c.lastName, c.age),
    根据查询结果进行填充*/ List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList(); System.out.println(result); }

    2)createNamedQuery方法//使用 @NamedQuery 标记的查询语句

    public void testNamedQuery(){
            Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(1, 3);
            Customer customer = (Customer) query.getSingleResult();
            System.out.println(customer);
    }
    @NamedQuery(name="testNamedQuery", query="FROM Customer c WHERE c.id = ?")//使用这个之后才能使用createNamedQuery
    @Cacheable(true)//开启缓存,兼与jpa的二级缓存策略
    @Table(name="JPA_CUTOMERS")//表名
    @Entity//实体
    public class Customer {}

    3)createNativeQuery方法//使用规范的sql

    public void testNativeQuery(){
            String sql = "SELECT age FROM jpa_cutomers WHERE id = ?";
            Query query = entityManager.createNativeQuery(sql).setParameter(1, 3);
            Object result = query.getSingleResult();
            System.out.println(result);
    }

    4)查询缓存

    String jpql = "FROM Customer c WHERE c.age > ?";
    Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);/*需要开启二级缓存(见jpa配置),在二级缓存中查找,假如解析后的sql语句一致,不会发送sql,直接使用缓存中的数据*/

    5)排序与分组

    分组

    String jpql = "SELECT o.customer FROM Order o GROUP BY o.customer HAVING count(o.id) >= 2;
    List<Customer> customers = entityManager.createQuery(jpql).getResultList();

    排序

    String jpql = "FROM Customer c WHERE c.age > ? ORDER BY c.age DESC";
    Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);

    6)连表查询

    String jpql = "FROM Customer c LEFT OUTER JOIN FETCH c.orders WHERE c.id = ?";  //其他一致,内联接,右连接
    Customer customer = (Customer) entityManager.createQuery(jpql).setParameter(1, 12).getSingleResult();

    7)子查询

        String jpql = "SELECT o FROM Order o WHERE o.customer = (SELECT c FROM Customer c WHERE c.lastName = ?)";
        Query query = entityManager.createQuery(jpql).setParameter(1, "YY");

    8)字符串处理函数:

    concat(String s1, String s2):字符串合并/连接函数。

    substring(String s, int start, int length):取字串函数。

    trim([leading|trailing|both,] [char c,] String s):从字符串中去掉首/尾指定的字符或空格。

    lower(String s):将字符串转换成小写形式。

    upper(String s):将字符串转换成大写形式。

    length(String s):求字符串的长度。

    locate(String s1, String s2[, int start]):从第一个字符串中查找第二个字符串(子串)出现的位置。若未找到则返回0。

    备注:其它基本上与hql一致,个人还是写sql写的比较多,然后使用类的方式也有//类找表

    8.spring整合jpa

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:tx="http://www.springframework.org/schema/tx"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    	<!-- 配置自动扫描的包 -->
    	<context:component-scan base-package="com.jpa"></context:component-scan>
    
    	<context:property-placeholder location="classpath:db.properties"/>
    
    	<bean id="dataSource"
    		class="com.mchange.v2.c3p0.ComboPooledDataSource">
    		<property name="user" value="${jdbc.user}"></property>
    		<property name="password" value="${jdbc.password}"></property>
    		<property name="driverClass" value="${jdbc.driverClass}"></property>
    		<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>		
    		<!-- 配置其他属性 -->
    	</bean>
    	
    	<!-- 配置 EntityManagerFactory -->
    	<bean id="entityManagerFactory"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<!-- 配置数据源 -->
              <property name="dataSource" ref="dataSource"></property> <!-- 配置 JPA 提供商的适配器. 可以通过内部 bean 的方式来配置 --> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean> </property> <!-- 扫描指定包下的@entitiy --> <property name="packagesToScan" value="com.jpa.spring.entities"></property> <!-- 配置 JPA 的基本属性. 例如 JPA 实现产品的属性(根据提供商的适配器) --> <property name="jpaProperties"> <props> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 配置 JPA 使用的事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"></property> </bean> <!-- 配置支持基于注解是事务配置 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>

     测试

    public class Test {
    	private  static ApplicationContext  ctx=null;
    	{
    		ctx= new ClassPathXmlApplicationContext("application.xml");
    	}
    	
    	@org.junit.Test
    	public  void   testC3p0(){
    		ComboPooledDataSource bean = ctx.getBean(ComboPooledDataSource.class);
    		System.out.println(bean);
    	}
    	
    	@org.junit.Test
    	public  void testEntity() throws SQLException{
    		LocalContainerEntityManagerFactoryBean lcemf = ctx.getBean(LocalContainerEntityManagerFactoryBean.class);
    		DataSource dataSource = lcemf.getDataSource();
    		Connection connection = dataSource.getConnection();
    		System.out.println(connection);
    	}
    }
    @org.junit.Test
    	public  void testEntity() throws SQLException{
    		LocalContainerEntityManagerFactoryBean lcemf = ctx.getBean(LocalContainerEntityManagerFactoryBean.class);
    //		DataSource dataSource = lcemf.getDataSource();
    //		Class<? extends EntityManager> entityManagerInterface = lcemf.getEntityManagerInterface();
    		EntityManagerFactory en = lcemf.getNativeEntityManagerFactory();
    		EntityManager manager = en.createEntityManager();
    		EntityTransaction transaction = manager.getTransaction();
    		transaction.begin();
    			Person person = new  Person();
    			person.setBrith(new Date());
    			person.setEamil("11@11");
    			person.setLastName("john");
    			manager.persist(person);
    		transaction.commit();
    		manager.close();
    		en.close();
    //		if(lcemf  instanceof  EntityManager){//false
    //			System.out.println(true);
    //		}
    //		Connection connection = dataSource.getConnection();
    //		System.out.println(connection);		
    	}
    

    综上所述有以下的结论

    @Repository
    public class PersonDao {
    
    	@PersistenceContext//上述测试类的一系列代码,应为LocalContainerEntityManagerFactoryBean不是EntityManager
    	private EntityManager entityManager;
    	
    	public void save(Person person){
    		entityManager.persist(person);
    	}
    	
    }
    
  • 相关阅读:
    gym 101064 G.The Declaration of Independence (主席树)
    hdu 4348 To the moon (主席树 区间更新)
    bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)
    ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(线段树)
    hdu 4417 Super Mario (主席树)
    poj 2236 Wireless Network (并查集)
    查看 scala 中的变量数据类型
    彻底搞定Maven
    Spark :【error】System memory 259522560 must be at least 471859200 Error initializing SparkContext.
    ip地址、子网掩码、网关与网卡、DNS的区别及用处
  • 原文地址:https://www.cnblogs.com/gg128/p/9733802.html
Copyright © 2011-2022 走看看