Hibernate实战(第二版)笔记----第三章--域模型与元数据

来源:互联网 发布:渠道管控管理系统源码 编辑:程序博客网 时间:2024/06/18 00:56

本章主要讲了域模型和元数据,以一个CaveatEmptor在线拍卖系统为例讲解了从项目架构分层,分析业务域,域模型,域模型的持久化类和持久化层之间的关注点完全分离,持久化类不清楚-且不依赖-持久化机制,然后讲解了域模型域元数据的关系,以及在运行时的方法方式。

域模型:被创建的实体类与属性被称为域模型.

元数据:即告知Hibernate持久化类及其属性与数据库表和列关联起来的方式。


JPA提供了两个元数据选项:

1、注解

2、XML描述符

    

JPA提供的访问持久化元模型API:

1、JAVA持久化中的动态元模型API

2、使用一个静态元模型


CaveatEmptor示例


CaveatEmptor是一个揭示ORM技术和Hibernate功能的在线拍卖应用,其中域模型为:




所对应的实体类为:




/model/src/main/java/org/jpwh/model/simple/Item.java

package org.jpwh.model.simple;import javax.persistence.Entity;import javax.persistence.FetchType;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.ManyToOne;import javax.persistence.Transient;import javax.persistence.Version;import javax.validation.constraints.Future;import javax.validation.constraints.NotNull;import javax.validation.constraints.Size;import java.math.BigDecimal;import java.util.Date;import java.util.HashSet;import java.util.Set;@Entitypublic class Item {    @Id    @GeneratedValue(generator = "ID_GENERATOR")    protected Long id;    public Long getId() { // 可选但有用        return id;    }    @Version    protected long version;    @NotNull    @Size(        min = 2,        max = 255,        message = "Name is required, maximum 255 characters."    )    protected String name;    @Future    protected Date auctionEnd;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Date getAuctionEnd() {        return auctionEnd;    }    public void setAuctionEnd(Date auctionEnd) {        this.auctionEnd = auctionEnd;    }    protected BigDecimal buyNowPrice;    public BigDecimal getBuyNowPrice() {        return buyNowPrice;    }    public void setBuyNowPrice(BigDecimal buyNowPrice) {        this.buyNowPrice = buyNowPrice;    }    @Transient    protected Set<Bid> bids = new HashSet<Bid>();    public Set<Bid> getBids() {        return bids;    }    public void setBids(Set<Bid> bids) {        this.bids = bids;    }    @ManyToOne(fetch = FetchType.LAZY)    protected Category category;    public Category getCategory() {        return category;    }    public void setCategory(Category category) {        this.category = category;    }    public void addBid(Bid bid) {        // Be defensive        if (bid == null)            throw new NullPointerException("Can't add null Bid");        if (bid.getItem() != null)            throw new IllegalStateException("Bid is already assigned to an Item");        getBids().add(bid);        bid.setItem(this);    }    public Bid placeBid(Bid currentHighestBid, BigDecimal bidAmount) {        if (currentHighestBid == null ||                bidAmount.compareTo(currentHighestBid.getAmount()) > 0) {            return new Bid(bidAmount, this);        }        return null;    }}


/model/src/main/java/org/jpwh/model/simple/Item_.java

package org.jpwh.model.simple;import java.util.Date;import javax.persistence.metamodel.SingularAttribute;@javax.persistence.metamodel.StaticMetamodel(Item.class)public abstract class Item_ {    public static volatile SingularAttribute<Item,Long> id;public static volatile SingularAttribute<Item,String> name;public static volatile SingularAttribute<Item,Date> auctionEnd;}


/model/src/main/java/org/jpwh/model/simple/Bid.java

package org.jpwh.model.simple;import org.jpwh.model.Constants;import javax.persistence.Entity;import javax.persistence.FetchType;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.validation.constraints.NotNull;import java.math.BigDecimal;@Entitypublic class Bid {    @Id    @GeneratedValue(generator = Constants.ID_GENERATOR)    protected Long id;    public Long getId() { // 可选的但是有用的        return id;    }    public Bid() {    }    @NotNull    protected BigDecimal amount;    public Bid(BigDecimal amount, Item item) {        this.amount = amount;        this.item = item;    }    public BigDecimal getAmount() {        return amount;    }    public void setAmount(BigDecimal amount) {        this.amount = amount;    }    @ManyToOne(optional = false, fetch = FetchType.LAZY) // NOT NULL    @JoinColumn(name = "ITEM_ID") // 实际上默认名称    protected Item item;    public Bid(Item item) {        this.item = item;        item.getBids().add(this); // 双向    }    public Item getItem() {        return item;    }    public void setItem(Item item) {        this.item = item;    }}

/model/src/main/java/org/jpwh/model/simple/Address.java

package org.jpwh.model.simple;import javax.persistence.Column;import javax.persistence.Embeddable;import javax.validation.constraints.NotNull;/** *  *而不是<code> @Entity </code>,该组件POJO标有<code> @Embeddable </code>。 它 *没有标识符属性。 */@Embeddablepublic class Address {    @NotNull // 忽略了DDL生成!    @Column(nullable = false) // 用于DDL生成!    protected String street;    @NotNull    @Column(nullable = false, length = 5) // Override VARCHAR(255)    protected String zipcode;    @NotNull    @Column(nullable = false)    protected String city;    /**     *Hibernate会调用这个无参数的构造函数来创建一个实例,然后     *直接填充字段。     */    protected Address() {    }    /**     *为方便起见,您可以拥有其他(public)构造函数。          **/    public Address(String street, String zipcode, String city) {        this.street = street;        this.zipcode = zipcode;        this.city = city;    }    public String getStreet() {        return street;    }    public void setStreet(String street) {        this.street = street;    }    public String getZipcode() {        return zipcode;    }    public void setZipcode(String zipcode) {        this.zipcode = zipcode;    }    public String getCity() {        return city;    }    public void setCity(String city) {        this.city = city;    }}

/model/src/main/java/org/jpwh/model/simple/Category.java

package org.jpwh.model.simple;import org.jpwh.model.Constants;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;@Entitypublic class Category {    @Id    @GeneratedValue(generator = Constants.ID_GENERATOR)    protected Long id;    public Long getId() {        return id;    }    protected String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

提供的一些测试类:




/examples/src/test/java/org/jpwh/test/simple/AccessJPAMetamodel.java

package org.jpwh.test.simple;import org.jpwh.env.JPATest;import org.jpwh.model.simple.Item;import org.jpwh.model.simple.Item_;import org.testng.annotations.Test;import javax.persistence.EntityManager;import javax.persistence.EntityManagerFactory;import javax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Path;import javax.persistence.criteria.Root;import javax.persistence.metamodel.Attribute;import javax.persistence.metamodel.ManagedType;import javax.persistence.metamodel.Metamodel;import javax.persistence.metamodel.SingularAttribute;import javax.persistence.metamodel.Type;import javax.transaction.UserTransaction;import java.util.Date;import java.util.List;import java.util.Set;import static org.testng.Assert.assertEquals;import static org.testng.Assert.assertFalse;//JPA访问元模型public class AccessJPAMetamodel extends JPATest {    @Override    public void configurePersistenceUnit() throws Exception {        configurePersistenceUnit("SimpleXMLCompletePU");    }    @Test    public void accessDynamicMetamodel() throws Exception {        EntityManagerFactory entityManagerFactory = JPA.getEntityManagerFactory();        Metamodel mm = entityManagerFactory.getMetamodel();        Set<ManagedType<?>> managedTypes = mm.getManagedTypes();        assertEquals(managedTypes.size(), 1);        ManagedType itemType = managedTypes.iterator().next();        assertEquals(            itemType.getPersistenceType(),            Type.PersistenceType.ENTITY        );        SingularAttribute nameAttribute =            itemType.getSingularAttribute("name");        assertEquals(            nameAttribute.getJavaType(),            String.class        );        assertEquals(            nameAttribute.getPersistentAttributeType(),            Attribute.PersistentAttributeType.BASIC        );        assertFalse(            nameAttribute.isOptional() // NOT NULL        );        SingularAttribute auctionEndAttribute =            itemType.getSingularAttribute("auctionEnd");        assertEquals(            auctionEndAttribute.getJavaType(),            Date.class        );        assertFalse(            auctionEndAttribute.isCollection()        );        assertFalse(            auctionEndAttribute.isAssociation()        );    }    @Test    public void accessStaticMetamodel() throws Exception {        SingularAttribute nameAttribute = Item_.name;        assertEquals(            nameAttribute.getJavaType(),            String.class        );    }    @Test    public void queryStaticMetamodel() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager entityManager = JPA.createEntityManager();            Item itemOne = new Item();            itemOne.setName("This is some item");            itemOne.setAuctionEnd(new Date(System.currentTimeMillis() + 100000));            entityManager.persist(itemOne);            Item itemTwo = new Item();            itemTwo.setName("Another item");            itemTwo.setAuctionEnd(new Date(System.currentTimeMillis() + 100000));            entityManager.persist(itemTwo);            tx.commit();            entityManager.close();            entityManager = JPA.createEntityManager();            tx.begin();            CriteriaBuilder cb = entityManager.getCriteriaBuilder();            // This query is the equivalent of "select i from Item i"            CriteriaQuery<Item> query = cb.createQuery(Item.class);            Root<Item> fromItem = query.from(Item.class);            query.select(fromItem);            List<Item> items =                entityManager.createQuery(query)                    .getResultList();            assertEquals(items.size(), 2);            // "where i.name like :pattern"            Path<String> namePath = fromItem.get("name");            query.where(                cb.like(                    namePath, // Has to be a Path<String> for like() operator!                    cb.parameter(String.class, "pattern")                )            );            items =                entityManager.createQuery(query)                    .setParameter("pattern", "%some item%") // Wildcards!                    .getResultList();            assertEquals(items.size(), 1);            assertEquals(items.iterator().next().getName(), "This is some item");            query.where(                cb.like(                    fromItem.get(Item_.name), // Static Item_ metamodel!                    cb.parameter(String.class, "pattern")                )            );            items =                entityManager.createQuery(query)                    .setParameter("pattern", "%some item%") // Wildcard!                    .getResultList();            assertEquals(items.size(), 1);            assertEquals(items.iterator().next().getName(), "This is some item");            tx.commit();            entityManager.close();        } finally {            TM.rollback();        }    }}


/examples/src/test/java/org/jpwh/test/simple/CRUD.java

package org.jpwh.test.simple;import org.jpwh.env.JPATest;import org.jpwh.model.simple.Item;import org.testng.annotations.BeforeClass;import org.testng.annotations.Test;import javax.persistence.EntityManager;import javax.persistence.Query;import javax.transaction.UserTransaction;import java.util.Date;import java.util.List;import static org.testng.Assert.assertEquals;public class CRUD extends JPATest {    @Override    public void configurePersistenceUnit() throws Exception {        configurePersistenceUnit("SimplePU");    }    @Test    public void storeAndQueryItems() throws Exception {        storeAndQueryItems("findItems");    }    public void storeAndQueryItems(String queryName) throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            Item itemOne = new Item();            itemOne.setName("Item One");            itemOne.setAuctionEnd(new Date(System.currentTimeMillis() + 100000));            em.persist(itemOne);            Item itemTwo = new Item();            itemTwo.setName("Item Two");            itemTwo.setAuctionEnd(new Date(System.currentTimeMillis() + 100000));            em.persist(itemTwo);            tx.commit();            em.close();            tx.begin();            em = JPA.createEntityManager();            Query q = em.createNamedQuery(queryName);            List<Item> items = q.getResultList();            assertEquals(items.size(), 2);            tx.commit();            em.close();        } finally {            TM.rollback();        }    }}

/examples/src/test/java/org/jpwh/test/simple/CRUDMetadataHBMXML.java

package org.jpwh.test.simple;import org.testng.annotations.Test;//CRUD HBM XML元数据public class CRUDMetadataHBMXML extends CRUD {    @Override    public void configurePersistenceUnit() throws Exception {        configurePersistenceUnit("SimpleXMLHibernatePU", "simple/Native.hbm.xml");    }    @Test    @Override    public void storeAndQueryItems() throws Exception {        super.storeAndQueryItems("findItemsHibernate");    }}

/examples/src/test/java/org/jpwh/test/simple/CRUDMetadataOverrideXML.java

package org.jpwh.test.simple;import org.hibernate.SessionFactory;import org.testng.annotations.BeforeClass;import org.testng.annotations.Test;//CRUD XML元数据覆盖public class CRUDMetadataOverrideXML extends CRUD {    @Override    public void configurePersistenceUnit() throws Exception {        configurePersistenceUnit("SimpleXMLOverridePU");    }    @Test    @Override    public void storeAndQueryItems() throws Exception {        super.storeAndQueryItems();    }    @Test    public void checkMetadataOverride() throws Exception {        //使用Hibernate元数据API来查找覆盖SQL列的名称,JPA不    //支持访问SQL详细信息    // TODO:不知道如何使用Hibernate 5 API访问SQL映射详细信息...            /*        Property nameProperty = itemClass.getProperty("name");        Column nameColumn = (Column) nameProperty.getColumnIterator().next();        // 列的名称来自XML描述符        assertEquals(nameColumn.getName(), "ITEM_NAME");        // 但是Bean验证注释仍然被识别!        assertEquals(nameColumn.isNullable(), false);        assertEquals(nameColumn.getLength(), 255);        */    }}

/examples/src/test/java/org/jpwh/test/simple/CRUDMetadataXML.java

package org.jpwh.test.simple;import org.testng.annotations.BeforeClass;import org.testng.annotations.Test;//CRUD XML元数据public class CRUDMetadataXML extends CRUD {    @Override    public void configurePersistenceUnit() throws Exception {        configurePersistenceUnit("SimpleXMLCompletePU");    }    @Test    @Override    public void storeAndQueryItems() throws Exception {        super.storeAndQueryItems();    }}

/examples/src/test/java/org/jpwh/test/simple/MappingEmbeddables.java

package org.jpwh.test.simple;import org.jpwh.env.JPATest;import org.jpwh.model.simple.Address;import org.jpwh.model.simple.User;import org.testng.annotations.BeforeClass;import org.testng.annotations.Test;import javax.persistence.EntityManager;import javax.persistence.PersistenceException;import javax.transaction.UserTransaction;import java.util.logging.Level;import java.util.logging.Logger;import static org.testng.Assert.assertEquals;//映射可嵌入public class MappingEmbeddables extends JPATest {    private static final Logger LOG = Logger.getLogger(MappingEmbeddables.class.getName());    @Override    public void configurePersistenceUnit() throws Exception {        configurePersistenceUnit("SimplePU");    }    @Test    public void storeAndLoadUsers() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            User user = new User();            user.setUsername("johndoe");            Address homeAddress = new Address("Some Street 123", "12345", "Some City");            user.setHomeAddress(homeAddress);            em.persist(user);            tx.commit();            em.close();            tx.begin();            em = JPA.createEntityManager();            User u = em.find(User.class, user.getId());            assertEquals(u.getUsername(), "johndoe");            assertEquals(u.getHomeAddress().getStreet(), "Some Street 123");            tx.commit();            em.close();        } finally {            TM.rollback();        }    }    @Test(expectedExceptions = org.hibernate.exception.ConstraintViolationException.class)    public void storeAndLoadInvalidUsers() throws Throwable {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            User user = new User();            user.setUsername("johndoe");            Address homeAddress = new Address("Some Street 123", "12345", null); // NULL city!            user.setHomeAddress(homeAddress);            em.persist(user);            try {                // Hibernate尝试插入但失败                em.flush();              //注意:如果你尝试用tx.commit()和一个冲洗的副作用,你就不会              //得到ConstraintViolationException。Hibernate会在内部捕获它              //简单地将事务标记为回滚。            } catch (Exception ex) {                throw unwrapCauseOfType(ex, org.hibernate.exception.ConstraintViolationException.class);            }        } finally {            TM.rollback();        }    }}

/examples/src/test/java/org/jpwh/test/simple/MappingManyToOne.java

package org.jpwh.test.simple;import org.jpwh.env.JPATest;import org.jpwh.model.simple.Bid;import org.jpwh.model.simple.Item;import org.testng.annotations.BeforeClass;import org.testng.annotations.Test;import javax.persistence.EntityManager;import javax.transaction.UserTransaction;import java.math.BigDecimal;import static org.testng.Assert.assertEquals;//映射多对一public class MappingManyToOne extends JPATest {    @Override    public void configurePersistenceUnit() throws Exception {        configurePersistenceUnit("SimplePU");    }    @Test    public void storeAndLoadBids() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            //存储在一个持久性上下文(事务)            Item anItem = new Item();            anItem.setName("Example Item");            Bid firstBid = new Bid(new BigDecimal("123.00"), anItem);            Bid secondBid = new Bid(new BigDecimal("456.00"), anItem);            // 订单在这里很重要,Hibernate不够聪明了!            em.persist(anItem);            em.persist(firstBid);            em.persist(secondBid);            tx.commit();            em.close();            tx.begin();            em = JPA.createEntityManager();            Long BID_ID = firstBid.getId();            // 加载另一个持久性上下文            Bid someBid = em.find(Bid.class, BID_ID); // SQL SELECT          //初始化Item代理,因为我们调用getId(),它是          //未映射为标识符属性(the field is!)            assertEquals(someBid.getItem().getId(), anItem.getId()); // SQL SELECT            tx.commit();            em.close();        } finally {            TM.rollback();        }    }}

/examples/src/test/java/org/jpwh/test/simple/ModelOperations.java

package org.jpwh.test.simple;import org.jpwh.model.simple.Bid;import org.jpwh.model.simple.Item;import org.testng.annotations.Test;import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import javax.validation.ValidatorFactory;import java.util.Date;import java.util.Locale;import java.util.Set;import static org.testng.Assert.*;//模式操作public class ModelOperations {    @Test    public void linkBidAndItem() {        Item anItem = new Item();        Bid aBid = new Bid();        anItem.getBids().add(aBid);        aBid.setItem(anItem);        assertEquals(anItem.getBids().size(), 1);        assertTrue(anItem.getBids().contains(aBid));        assertEquals(aBid.getItem(), anItem);        // 再次用方便的方法        Bid secondBid = new Bid();        anItem.addBid(secondBid);        assertEquals(2, anItem.getBids().size());        assertTrue(anItem.getBids().contains(secondBid));        assertEquals(anItem, secondBid.getItem());    }    @Test    public void validateItem() {        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();        Validator validator = factory.getValidator();        Item item = new Item();        item.setName("Some Item");        item.setAuctionEnd(new Date());        Set<ConstraintViolation<Item>> violations = validator.validate(item);        // 我们有一个验证错误,拍卖结束日期不在将来!        assertEquals(1, violations.size());        ConstraintViolation<Item> violation = violations.iterator().next();        String failedPropertyName =                violation.getPropertyPath().iterator().next().getName();        assertEquals(failedPropertyName, "auctionEnd");        if (Locale.getDefault().getLanguage().equals("en"))            assertEquals(violation.getMessage(), "must be in the future");    }}

/examples/src/test/java/org/jpwh/test/simple/SimpleTransitions.java

package org.jpwh.test.simple;import org.hibernate.Session;import org.hibernate.jdbc.Work;import org.jpwh.env.JPATest;import org.jpwh.model.simple.Address;import org.jpwh.model.simple.Item;import org.jpwh.model.simple.User;import org.testng.annotations.Test;import javax.persistence.EntityManager;import javax.persistence.EntityManagerFactory;import javax.persistence.FlushModeType;import javax.persistence.PersistenceUnitUtil;import javax.transaction.Status;import javax.transaction.UserTransaction;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import java.util.HashSet;import java.util.Set;import java.util.concurrent.Callable;import java.util.concurrent.Executors;import static org.testng.Assert.*;import static org.testng.Assert.assertEquals;//简单的过渡public class SimpleTransitions extends JPATest {    @Override    public void configurePersistenceUnit() throws Exception {        configurePersistenceUnit("SimplePU");    }    @Test    public void basicUOW() {        EntityManager em = null;        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            em = JPA.createEntityManager(); // 应用程序管理            Item someItem = new Item();            someItem.setName("Some Item");            em.persist(someItem);            tx.commit(); // 同步/刷新持久性上下文        } catch (Exception ex) {            // 事务回滚,异常处理            try {                if (tx.getStatus() == Status.STATUS_ACTIVE                    || tx.getStatus() == Status.STATUS_MARKED_ROLLBACK)                    tx.rollback();            } catch (Exception rbEx) {                System.err.println("Rollback of transaction failed, trace follows!");                rbEx.printStackTrace(System.err);            }            throw new RuntimeException(ex);        } finally {            if (em != null && em.isOpen())                em.close(); // 你创建它,你关闭它!        }    }    @Test    public void makePersistent() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            EntityManager em;            tx.begin();            em = JPA.createEntityManager();            Item item = new Item();            item.setName("Some Item"); // Item#name is NOT NULL!            em.persist(item);            Long ITEM_ID = item.getId(); // Has been assigned            tx.commit();            em.close();            tx.begin();            em = JPA.createEntityManager();            assertEquals(em.find(Item.class, ITEM_ID).getName(), "Some Item");            tx.commit();            em.close();        } finally {            TM.rollback();        }    }    @Test    public void retrievePersistent() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            Item someItem = new Item();            someItem.setName("Some Item");            em.persist(someItem);            tx.commit();            em.close();            long ITEM_ID = someItem.getId();            {                tx.begin();                em = JPA.createEntityManager();                // Hit the database if not already in persistence context                Item item = em.find(Item.class, ITEM_ID);                if (item != null)                    item.setName("New Name"); // Modify                tx.commit(); // Flush: Dirty check and SQL UPDATE                em.close();            }            {                tx.begin();                em = JPA.createEntityManager();                Item itemA = em.find(Item.class, ITEM_ID);                Item itemB = em.find(Item.class, ITEM_ID); // Repeatable read                assertTrue(itemA == itemB);                assertTrue(itemA.equals(itemB));                assertTrue(itemA.getId().equals(itemB.getId()));                tx.commit(); // Flush: Dirty check and SQL UPDATE                em.close();            }            tx.begin();            em = JPA.createEntityManager();            assertEquals(em.find(Item.class, ITEM_ID).getName(), "New Name");            tx.commit();            em.close();        } finally {            TM.rollback();        }    }    @Test(expectedExceptions = org.hibernate.LazyInitializationException.class)    public void retrievePersistentReference() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            Item someItem = new Item();            someItem.setName("Some Item");            em.persist(someItem);            tx.commit();            em.close();            long ITEM_ID = someItem.getId();            tx.begin();            em = JPA.createEntityManager();            /* 如果持久性上下文已经包含具有给定标识符的<code> Item </code>                <code> Item </code>实例由<code> getReference()</code>返回,而不会触发数据库。                此外,如果目前正在管理具有该标识符的持久化实例<em>no</em>,那么一个空                占位符将由Hibernate代理生成。 这意味着<code> getReference()</code>不会                访问数据库,它不返回<code> null </code>,与<code> find()</code>不同。             */            Item item = em.getReference(Item.class, ITEM_ID);            /* JPA提供<code> PersistenceUnitUtil </code>辅助方法,例如<code> isLoaded()</code>                检测您是否使用未初始化的代理。            */            PersistenceUnitUtil persistenceUtil =                JPA.getEntityManagerFactory().getPersistenceUnitUtil();            assertFalse(persistenceUtil.isLoaded(item));            /* 一旦您在代理上调用任何方法,例如<code> Item#getName()</code>,                执行<code> SELECT </code>以完全初始化占位符。 这个规则的例外是                一种映射的数据库标识符getter方法,如<code> getId()</code>。 代理人                可能看起来像真实的东西,但它只是一个携带标识符值的占位符                它代表的实体实例。 如果代理服务器上不存在数据库记录                被初始化,将抛出一个<code> EntityNotFoundException </code>。             */            // assertEquals(item.getName(), "Some Item");            /*                Hibernate有一个方便的静态<code> initialize()</code>方法,加载代理的数据。             */            // Hibernate.initialize(item);            tx.commit();            em.close();            /* 在持久化上下文关闭之后,<code>item</code>处于分离状态。如果你这样做在持久化上下文仍然打开时,不初始化代理,如果你访问代理,您将得到一个<code> LazyInitializationException </code>。你不能加载,一旦持久化上下文关闭,就按需数据。解决方案很简单:加载关闭持久化上下文之前的数据。             */            assertEquals(item.getName(), "Some Item");        } finally {            TM.rollback();        }    }    @Test    public void makeTransient() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            Item someItem = new Item();            someItem.setName("Some Item");            em.persist(someItem);            tx.commit();            em.close();            long ITEM_ID = someItem.getId();            tx.begin();            em = JPA.createEntityManager();            /* 如果调用<code>find()</code>,Hibernate将执行<code>SELECT</code>                加载<code>Item</code>。 如果你调用<code> getReference()</code>,Hibernate                将尝试避免<code>SELECT</code>并返回代理。             */            Item item = em.find(Item.class, ITEM_ID);            //Item item = em.getReference(Item.class, ITEM_ID);            /*        调用<code>remove()</code>将队列化实体删除                工作单位完成,现在已被删除<em>removed</em>。如果<code>remove()</code>                在代理上调用,Hibernate将执行<code>SELECT</code>来加载数据。                实体实例必须在生命周期过渡期间完全初始化。 你可能是否启用了生命周期回调方法或实体侦听器                (请参阅<a href="#EventListenersInterceptors"/>),实例必须通过这些                拦截器完成其整个生命周期。             */            em.remove(item);            /*  被删除状态的实体不再处于持久状态,这可以是                 使用<code> contains()</code>操作进行检查。             */            assertFalse(em.contains(item));            /*                您可以使删除的实例再次持久化,取消删除。             */            // em.persist(item);            // hibernate.use_identifier_rollback已启用,它现在看起来像一个暂时的实例            assertNull(item.getId());            /* 当事务提交时,Hibernate会同步状态转换                数据库并执行SQL <code> DELETE </code>。 JVM垃圾收集器检测到                <code> item </code>不再被任何人引用,最后删除最后一个跟踪                数据。             */            tx.commit();            em.close();            tx.begin();            em = JPA.createEntityManager();            item = em.find(Item.class, ITEM_ID);            assertNull(item);            tx.commit();            em.close();        } finally {            TM.rollback();        }    }    @Test    public void refresh() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            Item someItem = new Item();            someItem.setName("Some Item");            em.persist(someItem);            tx.commit();            em.close();            final long ITEM_ID = someItem.getId();            tx.begin();            em = JPA.createEntityManager();            Item item = em.find(Item.class, ITEM_ID);            item.setName("Some Name");            // 有人更新数据库中的这一行!            Executors.newSingleThreadExecutor().submit(new Callable<Object>() {                @Override                public Object call() throws Exception {                    UserTransaction tx = TM.getUserTransaction();                    try {                        tx.begin();                        EntityManager em = JPA.createEntityManager();                        Session session = em.unwrap(Session.class);                        session.doWork(new Work() {                            @Override                            public void execute(Connection con) throws SQLException {                                PreparedStatement ps = con.prepareStatement("update ITEM set name = ? where ID = ?");                                ps.setString(1, "Concurrent Update Name");                                ps.setLong(2, ITEM_ID);                                /* 替代方法:在刷新时收到EntityNotFoundException                                PreparedStatement ps = con.prepareStatement("delete from ITEM where ID = ?");                                ps.setLong(1, ITEM_ID);                                */                                if (ps.executeUpdate() != 1)                                    throw new SQLException("ITEM row was not updated");                            }                        });                        tx.commit();                        em.close();                    } catch (Exception ex) {                        TM.rollback();                        throw new RuntimeException("Concurrent operation failure: " + ex, ex);                    }                    return null;                }            }).get();            String oldName = item.getName();            em.refresh(item);            assertNotEquals(item.getName(), oldName);            assertEquals(item.getName(), "Concurrent Update Name");            tx.commit(); // 刷新:脏检查和SQL UPDATE            em.close();        } finally {            TM.rollback();        }    }    @Test(groups = {"H2", "POSTGRESQL", "ORACLE"})    public void replicate() throws Exception {        Long ITEM_ID;        try {            UserTransaction tx = TM.getUserTransaction();            tx.begin();            EntityManager em = JPA.createEntityManager();            Item someItem = new Item();            someItem.setName("Some Item");            em.persist(someItem);            tx.commit();            em.close();            ITEM_ID = someItem.getId();        } finally {            TM.rollback();        }        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager emA = getDatabaseA().createEntityManager();            Item item = emA.find(Item.class, ITEM_ID);            EntityManager emB = getDatabaseB().createEntityManager();            emB.unwrap(Session.class)                .replicate(item, org.hibernate.ReplicationMode.LATEST_VERSION);            tx.commit();            emA.close();            emB.close();        } finally {            TM.rollback();        }    }    protected EntityManagerFactory getDatabaseA() {        return JPA.getEntityManagerFactory();    }    protected EntityManagerFactory getDatabaseB() { // TODO:失败,因为我们不能在同一事务中招募两个非XA连接     //在MySQL上 XA在MySQL中破坏,所以我们必须使用Bitronix XA包装器,它可以         //每个事务只处理一个非XA资源。 请参阅DatabaseProduct.java        return JPA.getEntityManagerFactory();    }    @Test    public void flushModeType() throws Exception {        UserTransaction tx = TM.getUserTransaction();        Long ITEM_ID;        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            Item someItem = new Item();            someItem.setName("Original Name");            em.persist(someItem);            tx.commit();            em.close();            ITEM_ID = someItem.getId();        } finally {            TM.rollback();        }        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            Item item = em.find(Item.class, ITEM_ID);            item.setName("New Name");            // 禁用刷新之前查询:            em.setFlushMode(FlushModeType.COMMIT);            assertEquals(                em.createQuery("select i.name from Item i where i.id = :id")                    .setParameter("id", ITEM_ID).getSingleResult(),                "Original Name"            );            tx.commit(); // Flush!            em.close();        } finally {            TM.rollback();        }    }    @Test    public void scopeOfIdentity() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            Item someItem = new Item();            someItem.setName("Some Item");            em.persist(someItem);            tx.commit();            em.close();            long ITEM_ID = someItem.getId();            tx.begin();            em = JPA.createEntityManager();            Item a = em.find(Item.class, ITEM_ID);            Item b = em.find(Item.class, ITEM_ID);            assertTrue(a == b);            assertTrue(a.equals(b));            assertEquals(a.getId(), b.getId());            tx.commit();            em.close();            // PC is gone, 'a' and 'b' are now references to instances in detached state!            tx.begin();            em = JPA.createEntityManager();            Item c = em.find(Item.class, ITEM_ID);            assertTrue(a != c); // The 'a' reference is still detached!            assertFalse(a.equals(c));            assertEquals(a.getId(), c.getId());            tx.commit();            em.close();            Set<Item> allItems = new HashSet<>();            allItems.add(a);            allItems.add(b);            allItems.add(c);            assertEquals(allItems.size(), 2); // 这似乎是错的和任意的!        } finally {            TM.rollback();        }    }    @Test    public void detach() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            User someUser = new User();            someUser.setUsername("johndoe");            someUser.setHomeAddress(new Address("Some Street", "1234", "Some City"));            em.persist(someUser);            tx.commit();            em.close();            long USER_ID = someUser.getId();            tx.begin();            em = JPA.createEntityManager();            User user = em.find(User.class, USER_ID);            em.detach(user);            assertFalse(em.contains(user));            tx.commit();            em.close();        } finally {            TM.rollback();        }    }    @Test    public void mergeDetached() throws Exception {        UserTransaction tx = TM.getUserTransaction();        try {            tx.begin();            EntityManager em = JPA.createEntityManager();            User detachedUser = new User();            detachedUser.setUsername("foo");            detachedUser.setHomeAddress(new Address("Some Street", "1234", "Some City"));            em.persist(detachedUser);            tx.commit();            em.close();            long USER_ID = detachedUser.getId();            detachedUser.setUsername("johndoe");            tx.begin();            em = JPA.createEntityManager();            User mergedUser = em.merge(detachedUser);            // 合并后丢弃'detachUser'引用!            // 'mergedUser'处于持久状态            mergedUser.setUsername("doejohn");            tx.commit(); // UPDATE在数据库中            em.close();            tx.begin();            em = JPA.createEntityManager();            User user = em.find(User.class, USER_ID);            assertEquals(user.getUsername(), "doejohn");            tx.commit();            em.close();        } finally {            TM.rollback();        }    }}


阅读全文
0 0
原创粉丝点击