hibernate笔记--JPA操作

笔记5

JPA单表操作

可以省去配置每个实体类的.xml文件,用注解的方式在实体类中直接说明就可以了

1.主要配置:

注意:此配置文件必须在src的根目录下边,文件名必须是perisistence.xml

其中的具体配置如下:

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

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence

         http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"

        version="2.1">

扫描二维码关注公众号,回复: 183770 查看本文章

        <!-- 配置持久化单元,可以配置多个,但是名称不能一样

        name:用来指定持久化单元名称

        transaction-type:事务类型

        JTA:是Javatransaction api

        RESOURCE_LOCAL:本地代码事务(用这个)

         -->

        <persistence-unit name="myJPAUnit"transaction-type="RESOURCE_LOCAL">

        <!-- JPA配置的提供商,可以不写-->

        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <!-- 指定JPA注解的实体类位置,可以不写-->

        <class>com.wbs.domain.Customer</class>

        <!-- 链接数据库相关的配置,都是hibernate的,只需要把hibernate之前的主配置文件中的内容拷贝即可 -->

       

        <properties>

         <!--第一部分:数据库的链接配置 -->

           <property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>

           <property name="hibernate.connection.url" value="jdbc:oracle:thin:@localhost:1521:ORCL"/>

           <property name="hibernate.connection.username" value="system"/>

           <property name="hibernate.connection.password" value="wbs19950305"/>

           <property name="hibernate.dialectt" value="org.hibernate.dialect.Oracle8iDialec"/>

           <!-- 第二部分:可选配置 -->

           <property name="hibernate.show_sql" value="true" />  <!-- 是否显示hibernate生成的sql语句 -->

           <property name="hibernate.format_sql" value="true"/><!-- 是否使用格式化输出sql语句到控制台 -->

           <!-- 配置hibernate使用何种语句生成DDL语句 -->

           <property name="hibernate.hbm2ddl.auto" value="update"/><!-- update表示检测实体类映射配置和表结构是否一致,如果不一致,更新表结构 -->

           <!-- 设置hibernate的连接池供应商-->

           <!-- <propertyname="hibernate.connection.provider_class" value=

           org.hibernate.connection.C3P0ConnectionProvider/>  -->

           </properties>

        </persistence-unit>

</persistence>

2.获取JPA操作数据库的对象:

其中的createEntityManagerFactory()方法中的参数必须要和persistence.xml中的持久化单元名称一致。

//相当于SessionFactory

    privatestatic EntityManagerFactory factory;

    static {

       factory=Persistence.createEntityManagerFactory("myJPAUnit");

    }

    //获取JPA操作数据库的对象

    publicstatic EntityManagercreateEntityManager(){

       returnfactory.createEntityManager();

    }

3.具体的操作

/**

 * JPA入门案例

 * JPA单表操作

 * @author bo

 *

 */

publicclass JPAtest {

    //保存

    @Test

    publicvoid test1(){

       Customer c=new Customer();

       c.setCusName("JPA客户1");

       //1.获取EntityManager对象

       EntityManager em=JPAUtils.createEntityManager();

       //获取事务对象,并开启事务

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //执行保存操作

       em.persist(c);

       //提交事务

       tx.commit();

       //关闭资源

       em.close();

    }

   

    //查找操作,

    @Test

    publicvoid test2(){

       //find是立即加载

       //1.获取EntityManager对象

       EntityManager em=JPAUtils.createEntityManager();

       //获取事务对象,并开启事务

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //需要把更新的数据查找出来

       Customer c=em.find(Customer.class, 161L);

       System.out.print(c);

       //提交事务

       tx.commit();

       //关闭资源

       em.close();

    }

   

    //更新操作

    @Test

    publicvoid test3(){

       //1.获取EntityManager对象

       EntityManager em=JPAUtils.createEntityManager();

       //获取事务对象,并开启事务

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //需要把更新的数据查找出来

       Customer c=em.find(Customer.class, 161L);

       //修改客户的地址为大连

       c.setCusAddress("大连");

       //提交事务

       tx.commit();

       //关闭资源

       em.close();

    }

    //更新的另一种方式

    //merge合并并更新

    @Test

    publicvoid test4(){

       //1.获取EntityManager对象

       EntityManager em=JPAUtils.createEntityManager();

       //获取事务对象,并开启事务

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //需要把更新的数据查找出来

       Customer c=em.find(Customer.class, 162L);

       //修改客户的地址为大连

       c.setCusAddress("dlmu");

       em.merge(c);

       //提交事务

       tx.commit();

       //关闭资源

       em.close();

    }

   

    //删除操作

    @Test

    publicvoid test5(){

       //1.获取EntityManager对象

       EntityManager em=JPAUtils.createEntityManager();

       //获取事务对象,并开启事务

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //需要把更新的数据查找出来

       Customer c=em.find(Customer.class, 161L);

       em.remove(c);

       //提交事务

       tx.commit();

       //关闭资源

       em.close();

    }

    //查询所有

    /**

     * 涉及的对象是:JPAQuery

     * 如何获取该对象:

     *     EntityManagercreateQuery(Stringjpql)方法

     * 参数的含义:

     *     jpql:Java Persistence Query Language

     *     写法和HQL相似,也是把表明换成类名,把字段名换成属性名,

     *     它在写查询所有时候不能使用 "from 实体类名"

     *     需要使用select关键字

     *         select c from Customer c //前一个c是别名

    */

    @Test

    publicvoid test6(){

       //1.获取EntityManager对象

       EntityManager em=JPAUtils.createEntityManager();

       //获取事务对象,并开启事务

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //获取JPAQUERY对象

       Query query=em.createQuery("selectc from Customer c where cusName like ?1 and cusLevel=?2");

       //给占位符赋值

       query.setParameter(1,"%大连%");

       query.setParameter(2, "23");

       //执行方法,获取结果集

       List list=query.getResultList();

       for(Object o:list){

           System.out.println(o);

       }

       //提交事务

       tx.commit();

       //关闭资源

       em.close();

    }

说明:

1. persist()方法相当于是save()操作;

2. remove()对应的是delete();

3. find()方法对应get()方法;

4. getReference()是延迟加载;

5. find()是立即加载;

6. uniqueResult()对应getSingleResult(),返回唯一的结果。

7. merge()和update()相似,但是merge干的活update有些不能干;

8. 下边说明merge和update的不同:

当查询了一个对象,关闭了session,有查询了该对象,有修改了该对象,此时如果用update方法的时候会报错,因为第一次查完后对象的状态转变成了托管态,而在此查询该对象,修改的时候是持久态,此时对象的状态时不一样的,在一级缓存外边还有一个改对象,如果此时更新的话,因为两个的对象的OID是一样的,但是却发生了修改,此时若Update的话,两个对象是不能合并的,只能用merge()方法将其更新,即将两个对象合并了。

    /**

     * 查询ID3的客户

     * 关闭session(清空了一级缓存和快照)

     * 修改id1的客户的名称为英华5公寓

     * 在此获取session

     * 再次查询ID1的客户

     *  更新刚才修改的客户

     */

    @Test

    publicvoid test1(){

       Session s=HibernateUtils.openSession();

       Transaction tx=s.beginTransaction();

       Customer c=s.get(Customer.class, 1L);//持久态

       tx.commit();

       s.close();

       //修改客户信息

       c.setCusname("英华5公寓");//托管态

       Session s1=HibernateUtils.openSession();

       Transaction tx1=s.beginTransaction();

       //再次查询

       Customer c1=s.get(Customer.class, 1L);//持久态

       //更新操作

       //s1.update(c);//将托管态转换为持久态,update方法是不行的,必须要用到merge方法才可以的

       s1.merge(c);

       tx1.commit();

       s1.close();

    }

JPA一对多表操作

1.     一对多实体类的注解写法:

 /**

 * 客户的实体类

 * 使用的注解都是JPA规范下的,所以导包,都需要导入javax.persistence下的包

 */

@Entity//表明该类是一个实体类

@Table(name="jpa_cus_customer")//建立当前类和数据库表的对应关系

publicclass Customer implements Serializable {

    @Id//表明当前字段是一个主键

    @Column(name="cust_id")//表明对应的数据库的主键字段是cus_id

    @GeneratedValue(strategy=GenerationType.SEQUENCE)//请指定主键生成策略.strategy:使用JPA提供的主键生成策略,此属性用不了。generator:可以使用hibernate中的主键生成策略

    private Long cusId;

   

    @Column(name="cust_name")

    private String cusName;

   

    @Column(name="cust_source")

    private String cusSource;

   

    @Column(name="cust_industry")

    private String cusIndustry;

   

    @Column(name="cust_level")

    private String cusLevel;

   

    @Column(name="cust_address")

    private String cusAddress;

   

    @Column(name="cust_phone")

    private String cusPhone;

   

    //一对的哟关系映射:一个客户可以有多个联系人

    @OneToMany(targetEntity=LinkMan.class,mappedBy="customer")//mappedBy是映射来自,相当于inverse,即主表不在关心从表的信息,让联系人去维护

    private Set<LinkMan> linkmans=new HashSet<LinkMan>(0);

2. JPA实现一对多插入操作

JPA操作值插入了两条记录,而不会有update语句, 因为在主表中已经mappedBy="customer"放弃维护了

    /**

     * 保存操作

     *     创建一个客户和一个联系人

     *     建立客户和联系人之间的关系

     *     先保存客户,再保存联系人

     */

    @Test

    publicvoid test1(){

       Customer c=new Customer();

       LinkMan l=new LinkMan();

       c.setCusName("JPA One To ManyCustomer");

       l.setLkmName("JPA Many To OneLinkMan");

       c.getLinkmans().add(l);

       l.setCustomer(c);

       EntityManager em=JPAUtils.createEntityManager();

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       em.persist(c);

       em.persist(l);

       tx.commit();

       em.close();

    }

3. JPA的更新操作

 此时必须要配置级联操作:想级联操作谁就应该在谁的上边进行注解配置cascade=CsacadeType.PERSIST属性,即保存或者更新客户的同时保存联系人,

但时cascade=CsacadeType.PERSIST只是级联更新

@OneToMany(targetEntity=LinkMan.class,mappedBy="customer",cascade=CascadeType.PERSIST)//mappedBy是映射来自,相当于inverse,即主表不在关心从表的信息,让联系人去维护

private Set<LinkMan> linkmans=new HashSet<LinkMan>(0);

    /**

     * 更新操作

     * 新建联系人

     * 查询ID186的客户

     * 为这个人分配联系人

     * 更新客户

     */

    @Test

    publicvoid test2(){

       LinkMan l=new LinkMan();

       l.setLkmName("JPA Many To One LinkMan3333");

       EntityManager em=JPAUtils.createEntityManager();

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       Customer c=em.find(Customer.class,185L);

       c.getLinkmans().add(l);

       l.setCustomer(c);

       //em.merge(l);//这句可以不写,因为有快照机制,会自己更新的

       tx.commit();

       em.close();

}

4.JPA的删除操作

         1.删除操作

         删除主表:若在客户上边配置了放弃维护,即mappedBy="customer",直接删除指标会报错

        此时还想要删除的话,需要配置cascade=CascadeType.DELET或者cascade=CascadeType.ALL就可以删除

          需要注意的是:联系人那边(从表)也可以配置cascade=CascadeType.ALL这些东西

     

    @Test

    publicvoid test3(){

       EntityManager em=JPAUtils.createEntityManager();

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       Customer c=em.find(Customer.class,185L);

       em.remove(c);

       tx.commit();

       em.close();

    }

JPA的查询操作

JPA中也可以使用对象导航查询,也可以设置查询的时机

延迟加载的特点:真正用到该对象的时候才开始查询改对象的属性

1.如果是立即加载,需要在Customer的set集合的注解中加入下边的语句:fetch=FetchType.EAGER其原理是利用了左外连接查询的方式实现了立即加载。没写是EAGER,即默认是EAGER。LinkMan中也可是设置成立即加载。

@OneToMany(targetEntity=LinkMan.class,mappedBy="customer",cascade=CascadeType.ALL,fetch=FetchType.EAGER)//mappedBy是映射来自,相当于inverse,即主表不在关心从表的信息,让联系人去维护

    private Set<LinkMan>linkmans=new HashSet<LinkMan>(0);

下边的查询可以设置成立即加载,也可以设置成延迟加载

    /**

     * 根据客车讯客户下边的联系人

     */

    @Test

    publicvoid test1(){

       EntityManager em=JPAUtils.createEntityManager();

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //1.查询ID1的客户

       Customer c=em.find(Customer.class, 1L);

       System.out.println(c);

       System.out.print(c.getLinkmans());

      

       tx.commit();

       em.close();

    }

    /**

     * 根据联系人查询客户

     */

    @Test

    publicvoid test2(){

       EntityManager em=JPAUtils.createEntityManager();

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //1.查询ID1的客户

       LinkMan l=em.find(LinkMan.class, 1L);

       System.out.println(l);

       Customer c=l.getCustomer();

       System.out.print(c);

       tx.commit();

       em.close();

    }

JPA的多对多

1.在角色实体对象中,如果配置了中间表的表名和在中间表中的列明,则在另外多的一方中只需要配置@ManyToMany(mappedBy="users")//谁写mappedBy谁就不在关心创建中间表了,即让另外一方不在关心创建中间表。

@Entity

@Table(name="jpa_sysrole")

publicclass SysRole implements Serializable {

    @Id

    @Column(name="role_id")

    @GenericGenerator(name="aa",strategy="uuid")//声明一个主键生成策略的生成器name:给生成器起名字;strategy:指定Hibernate中包含的主键生成策略

    @GeneratedValue(generator="aa")

    private Long roleId;

   

    @Column(name="role_name")

    private String roleName;

   

    @Column(name="role_memo")

    private String roleMemo;

    //多对多关系映射,一个角色可以赋给多个用户

@JoinTable(name="jpa_user_role",joinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")},//joinColumns写的是当前实体在中间表中的晚间字段

       inverseJoinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")}//inverseJoinColumns写的是对方实体在中间表中的晚间字段

   

           )

    private Set<SysUser> users=newHashSet<SysUser>(0);

其中黄色标出的是多对多的关系中特殊的配置,需要注意。

SysUser的主要配置如下,即一方不再关心中间表的创建的事情,只交给一个多方去管。

    @ManyToMany(mappedBy="users")//谁写mappedBy谁就不在关心创建中间表了

private Set<SysRole>roles=new HashSet<SysRole>(0);

2.多对多的操作

 

/**

 * JPA的多对多操作

 *     保存操作

 *     删除操作

 */

publicclass JPADemo1 {

    /**

     * 保存操作

     *     常见两个用户

     *     创建三个角色

     *     让一号用户具有1,2号角色

     *     2号用户具备2,3号角色

     *     保存用户和角色

     */

    @Test

    publicvoid test1(){

       SysUser u1=new SysUser();

       u1.setUserName("JPA Many To ManyUser1");

       SysUser u2=new SysUser();

       u2.setUserName("JPA Many To ManyUser2");

       SysRole r1=new SysRole();

       r1.setRoleName("JPA Many To ManyRole1");

       SysRole r2=new SysRole();

       r2.setRoleName("JPA Many To ManyRole2");

       SysRole r3=new SysRole();

       r3.setRoleName("JPA Many To ManyRole3");

      

       //建立用户角色之间的关系

       u1.getRoles().add(r1);

       u1.getRoles().add(r2);

       u2.getRoles().add(r2);

       u2.getRoles().add(r3);

      

       r1.getUsers().add(u1);

       r2.getUsers().add(u1);

       r2.getUsers().add(u2);

       r3.getUsers().add(u2);

       EntityManager em=JPAUtils.createEntityManager();

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //保存操作

       em.persist(u1);

       /*em.persist(u2);//如果设置了级联保存,则只需保存一个,其他的与它级联的都会自动保存

       em.persist(r1);

       em.persist(r2);

       em.persist(r3);*/

       tx.commit();

       em.close();

      

    }

    /**

     * 删除操作

     *     不管是Hibernate中还是JPA中,多对多都不能这样配置,这样会把所有的数据都删干净的

     */

    @Test

    publicvoid test2(){

       EntityManager em=JPAUtils.createEntityManager();

       EntityTransaction tx=em.getTransaction();

       tx.begin();

       //删除操作

       SysUser s=em.find(SysUser.class,"asdfasdfasdfasd");//因为此时用的是UUID,必须要写清楚具体的那个用户ID,而不能写出第几个

       tx.commit();

       em.close();

    }

注意:多对多的级联保存配置如下(需要在每一个实体类中配置),下边只写了一个实体类总的cascade的配置,另外的多表的cascade配置都应改如此

@ManyToMany(cascade=CascadeType.ALL)//多对多关系映射,一个角色可以赋给多个用户

     //多对多关系映射,一个角色可以赋给多个用户

@JoinTable(name="jpa_user_role",joinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")},//joinColumns写的是当前实体在中间表中的晚间字段

               inverseJoinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")})//inverseJoinColumns写的是对方实体在中间表中的晚间字段

     private Set<SysUser>users=new HashSet<SysUser>(0);

3.JPA中的c3p0操作

    @Test

    publicvoid test1(){

       //1.获取JPA中的操作对象

       EntityManager em=JPAUtils.createEntityManager();

       //2.em转换成session

       Session session=em.unwrap(Session.class);

       //验证c3p0连接池是否配置成功

       //3.执行sessiondoWork()方法

       session.doWork(new Work(){

 

           @Override

           publicvoid execute(Connection conn) throws SQLException {

              System.out.println(conn.getClass().getName());

           }

          

       });

    }

但是要导入c3p0的JAR包,而且要在配置文件里面协商c3p0的供应商:

<property name="hibernate.connection.provider_class"

value="org.hibernate.connection.C3P0ConnectionProvider"/> 

如果要从JPA中得到Session对象的话,需要对EntityManager进行unwrap()操作(解包装),就可以得到Session对象,而且用doWork()方法可以得到Connection对象,可以对它进行操作。

4.  JPA中使用单线程

自己手写单线程代码,想要使用JPA自己的,需要配置Spring使用。

下边是写出单线程的代码:

 publicclass JPAUtils {

    //相当于SessionFactory

    privatestatic EntityManagerFactory factory;

    static {

       factory=Persistence.createEntityManagerFactory("myJPAUnit");

       tl=new ThreadLocal<EntityManager>();

    }

    //获取JPA操作数据库的对象

    /*public static EntityManager createEntityManager(){

       returnfactory.createEntityManager();//此时不是单线程的EntityManager

    }*/

    publicstaticvoid main(String[] args) {

       createEntityManager();

    }

     //自己写代码让始终有一个EntityManager

     privatestatic ThreadLocal<EntityManager> tl;

     static{

         factory=Persistence.createEntityManagerFactory("myJPAUnit");

         tl=new ThreadLocal<EntityManager>();

     }

     publicstatic EntityManager createEntityManager(){

         //1.从当前线程上获取EntityManager对象

         EntityManager em=tl.get();

         if(tl==null){

             em=factory.createEntityManager();

             tl.set(em);

         }

         returntl.get() ; //此时是单线程的EntityManager

}

}

下边是测试单线程的代码:

    @Test

    publicvoid test2(){

       EntityManager em1=JPAUtils.createEntityManager();

       EntityManager em2=JPAUtils.createEntityManager();

       System.out.println(em1==em2);

    }

其测试结果为true。说明是一个线程。

Hibernate总结

HibernateJPA配置了的话也可以用Hibernate的方式来增删改查

猜你喜欢

转载自blog.csdn.net/itxiaobaibai/article/details/80145366
今日推荐