实体Bean: 持久化是位于JDBC之上的一个更高层抽象。持久层将对象映射到数据库,以便在查询、、装载、更新或删除对象的时候,无须使用想JDBC那样繁琐的API,在EJB的早期版本中,持久化是EJB平台的一部分。从EJB3.0开始,持久化已经自成规范,被称为Java Persistence API。 Java Persistence API定一个了一种方法,可以将常规的普通Java对象(POJO)映射到数据库,这些普通Java对象被称作entity bean。除了是用Java Persistence 元数据将其映射到数据库外,entity bean与其他Java类没有任何区别。事实上,创建一个Entity Bean对象相当与新建一条记录,删除一个Entity Bean会同时从数据库中删除对应记录,修改一个Entity Bean,容器会自动将Entity Bean的状态同步到数据库。 Java Perisitence API还定义了一种查询语言(JPQL),具有与SQL相类似的特征,只不过做了裁剪,以便处理Java对象而非原始的关系scheme。 Jboss数据源的配置 数据源用于配置数据库的连接信息,每个数据源必须指定一个唯一的JNDI名称。应用通过JNDI名称找到数据源。在Jboss中,有一个默认的数据源DefaultDS,他使用Jboss内置的HSQLDB数据库。实际项目中可能使用不同的数据库,如MySql、SqlServer、Oracle等。每种数据库的数据源配置版可以在Jboss安装目录/docs/examples/jca目录中找到,名称为:数据库-ds.xml。 数据源配置文件的取名格式必须为xxx-ds.xml,如:mysql-ds.xml,oracle-ds.xml。数据源部署前,必须把数据库驱动Jar拷贝到[jboss安装目录]/server/default/lib。拷贝后,必须重启Jboss服务器。 MySql数据源的配置: 【mysql-ds.xml]】 <?xml version="1.0" encoding="UTF-8"?> <datasources> <local-tx-datasource> <jndi-name>MySqlDS</jndi-name> <connection-url>jdbc:mysql://localhost:3306/foshanshop</connection-url> <driver-class>com.mysql.jdbc.Driver</driver-class> <user-name>root</user-name> <password>aljoin</password> <!—最小的连接数 --> <min-pool-size>3</min-pool-size> <!—最大的连接数-- > <max-pool-size>32</max-pool-size> <!—抛出异常前最大的等待连接时间 -- > <bloking-timeout-millis>30000</blocking-timeout-millis> <!—关闭连接前连接空闲的最大时间 -- > <idel-timeout-minutes>5</idel-timeout-minutes> <exception-sorter-class-name> org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter </exception-sorter-class-name> <metadata> <type-mapping>mySQL</type-mapping> </metadata> </local-tx-datasource> </datasources> SqlServer数据源的配置: 【mssqlserver-ds.xml]】 <?xml version=”1.0” encoding=”UTF-8”?> <datasource> <local-tx-datasource> <jndi-name>MSSQLDS</jndi-name> <connectin-url> Jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=foshanshop </connection-url> <driver-class> Com.microsoft.jdbc.sqlserver.SQLServerDriver </driver-class> <user-name>sa</user-name> <password>sa</password> <metadata> <type-mapping>MS SQLSERVER2000</type-mapping> </metadata> </local-tx-datasource> </datasource> Oralce9i数据源的配置: 【oracle-ds.xml]】 <?xml version=”1.0” encoding=”UTF-8”?> <datasource> <local-tx-datasource> <jndi-name>OracleDS</jndi-name> <connection-url> Jdbc:oracle:thin:@192.168.1.2:1521:FS </connection-url> <driver-class> Oracle.jdbc.driver.OracleDriver <driver-class> <user-name>root</user-name> <password>root</password> <exception-sorter-class-name> Org.jboss.resource.adapter.jdbc.vendor.OracleExceptoiinSorter </exception-sorter-class-name> <metadata> <type-mapping>Oracle9i<type-mapping> </metadata> </local-tx-datasource> </datasource> 根据持久化规范的要求,以下部署描述文件是必须提供的,如果不提供这一文件,则持久化单元也将不存在,因此应用也不能够获得和使得EntityManager。我们需要将这一文件存放在虾类个类文件的META—INF目录下。 Persistence.xml文件指定实体Bean使用的数据源及EntityManager的默认行为。如下: <?xml version=”1.0 ”?> <persistence xmlns=http://java.sun.com/xml/ns/persistence Xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance Xsi:schemaLocation=”http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd” version=”1.0”> <persistence-unit name=”foshanshop” transaction-type=”JTA”> <jta-data-source>java:/DefaultMySqlDS</jta-data-source> <properties> <!—下面属性只是这对Jboss服务器-- > <property name=”hibernate.hbm2ddl.auto”value=”create-dorp”> </property> <!—调整JDBC抓去数量的大小:Statement.setFetchSize()--> <property name=”hibernate.jdbc.fetch_size” value=“”18/> <!—调整JDBC批量更新数量-- > <property name=”hibernate.jdbc.batch_size” value=”10”/> <!—显示最终执行的SQL-- > <property name=”hibernate.format_sql” value=”true”/> </properties> </persistence-unit> </persistence> ·Persistence-unit节点可以有一个或多个,每个persistence-unit借点定义了持久化内容名称,使用的数据源及持久化产品专有属性。 ·Name 属性定义了persistence-unit的名称,该属性是必须的。设置为数据库的名称 ·Transaction-type属性指定了persistence unit是受JTA事物管理并与之集成。还是 使用RESOURCE LOCAL的javax.persistence.EntityTransactionAPI来管理EntityManager实例的事物完整性。此属性在JavaEE环境中默认值是JTA,而在JavaSE环境中则为RESUOURCE_LOCAL。如果transaction-type=”JTA”,你可以使用<jta-data-source>指定数据源的JNDI名称。Jboss数据源的JNDI名称在局部名称空间。因此数据源名称前大小写铭感。 到此。我们知道persistence-unit将固定数量的一组类映射到数据库。 · 在MySql创建数据库时,必须指定数据库的字符集编码为GBK,否则当插入中文字符时会报:Data too long for column。 可以使用下面的SQL创建数据库: CREATE DATABASE ‘FOSHANSHOP’ DEFAULT CHARSET = GBK · 成员属性映射: 默认情况下,实体Bean的全部成员属性都会成为持久化字段。如果不希望一些成员属性成为持久化字段,可以使用@Transient注释标注。如: Public class Person implements Serializable{ …… @Transient Public String getFristName(){ return “xiaoling”;} } 如果你需要将枚举类型成员映射到数据库,可以使用@Enumerated注释进行标注。枚举类型成员属性可以被映射为字段窜形式(用EnumType.STRING指定),也可以映射为枚举值的数据序号(用EnumType.ORDINAL指定)。如下: Public enum CommentType{ NEWS{ public String getName(){return “资讯评论“;}}; PRODUCT{ public String getName(){return “产品评论”;}}; Public abstract String getName(); } @Entity Public class CommentContent implements Serializable{ …… Private CommentType type; //评论类型 @Enumerated(EnumType.STRING) Public CommentType getType(){ return type;} Public void setType (CommentType type){ this.type=type;} } 存放文件或大文本数据进数据库,JDBC使用java.sql.Blob类型存放二进制数据,java.sql.Clob类型存放字符数据。这些数据都非常占内存,@Lob注释作映射这些大数据类型,当属性的类型为byte[],Byte[]或java.io.Serializable时,@Lob注释将映射为数据库的Blob类型,当属性的类型为char[],Character[]或java.lang.String时,@Lob注释将映射为数据库Clob类型。在做内容管理系统时,我们通常会使用大文本数据,这时就有必要在字段或属性的getter方法标注@Lob. @Entity Public class News implements Serializable{ …… Private String content; @Lob Public String getContent(){ return content;} } 对于加了@Lob注释的大数据类型,为了避免每次加载实体时占用大量内存,我们有必要对该属性进行延迟加载,这是我们需要用到@Basic注释。其定义如下: Public @interface Basic{ FetchType fetch() default EAGER; //指定是否延迟加载,默认为立即加载 Boolean operational() default true; //生成数据库结构时字段是否允许为空 } @Entity Public class News implements Serializable{ …… Private String content; @Lob @Basic(fetch=FetchType.LAZY) Public String getContent(){ return content;} } 因为数据表对时间类型有更严格的划分,所以必须使用@Temporal注释指明java.util.Data或java.util.Calender类型的成员属性映射到数据库date、time和timestame中那种类型。注释的定义如下: Package javax.persistence; Public enum TemporatType{ DATE,TIME,TIMESTAMP } @Entity Public class person implements Serializable{ …… Private Date birthday; @Temporal(value=TemporalType.DATE) Public Date getBirthday(){ return birthday;} } 如果你不想将整个MyInfo对象映射进数据库,而只是想把MyInfo中的成员属性映射到数据库,你需要使用@Embedded注释。如: @Entity Public classs Prson Implemenst Serializable{ ...... @Embedded Public MyInfo getInfo(){ return info ;} } //另外还可以通过@javax.persistence.AttributeOverride注释重载MyInfo的成员属性的映射信息。如: @Entity Public class Person implements Serializable{ … @Embedded @AttributeOverride(name=”content”,column=@Column(length=1000)) Public MyInfo getInfo(){ return info ;} } //如果需要重载多个成员属性,可以和@javax.persistence.AttributeOverrides注释配合使用,如: @Entity Public class Person implements Serializable{ …… @Embedded @AttributeOverrides({ @AttirbuteOverride(name=”content”,column=@Column(length=100)), @AttirbuteOverride(name=”xxx”,column=@Column(length=10))}) Public MyInfo getInfo(){ return info; } } 持久化实体管理器EntityManager: 在Java persistence 规范中,EntityManager是为所有持久化操作提供服务的中枢(shu)。实体作为普通Java对象,只有在调用EntityManager将其持久化后,才会变成持久对象。EntityManager在一组固定的实体类与底层数据源之间进行O/R映射的管理,它可以用来添加/删除/更新实体Bean,通过主键查找实体bean,也可以通过JPQL语言查找满足条件的实体Bean。当EntityManager被注入到EJB时,EJB容器会对EntityManager所依赖的持久上下文(persistence context)具有完全的控制权。 持久化上下文(persistence context) 持久化上下文是有一组受托管(attached)的实体对象实例所构成的集合。它受EntityManager的管理。EntityManager跟踪persistence context 中所有对象的修改和更新情况,并根据指定的flush模式将这些修改保存到数据库中。一旦persistence context被关闭,所有实体对象都会脱离EntityManager而成为游离detached对象。对象一旦从persistence context中脱离,就不再受EntityManager管理了,任何对此对象的状态变更也不会被同步到数据库。Java persistence 中有两种类型的persistence context,分别是transaction-scoped 和extended persistence contexts。 实体对象拥有4中状态,这些状态通过调用EntityManager接口方法发生迁移: ·新建状态:该对象尚未拥有持久化主键,没有和一个持久化上下文关联。 ·托管状态:已经拥有持久化主键并和持久化上下文建立了联系。 ·游离状态:【detached】拥有持久化主键,但尚未和持久化上下文建立联系。 ·删除状态:拥有持久化主键,已经和持久化上下文建立联系,但已经被安排从数据库中删除。 1. 获取find()或getReference() Find()方法返回指定OID的实体。如果这个实体存在与当前的persistence context中,那么返回值是被缓存的对象;否则会创建一个新的实体,并从数据库中加载相关的持久状态。如果数据库不存在指定OID的记录,那么find()方法返回null。 getReference()方法与find()相似。不同的是:如果缓存中没有指定的实体,EntityManager会创建一个新的实体(实际上是实体的一个代理),hibernate采用CGLIB工具来生存实体类的代理类,但是不会立即访问数据库加载持久状态,而是在第一次访问某个持久属性的时候才加载相应的持久状态。此外getReference()方法不返回null,如果在数据库中找不到相应的实体,该方法会抛出javax.persistence.EntityNotFoundException(注,执行getReference()时并不会抛出该例外,该例外是在第一次访问实体属性时才会被抛出)。在某些场合下使用getReference()方法可以避免从数据库加载持久状态的性能开销。 em.remove(em.getReference(Person.class,1)); //删除指定对象 em.remove(em.find(Person.class,1)); //先查找后删除 JPQL操作createQuery(): 除了可以使用find()或getReference()获取实体Bean之外,你还可以使用JPQL查询获取实体Bean,要执行JPQL语句,你可以通过createQuery()方法创建一个Query对象。 @PersistenceContext protected EntityManager em; … Query query = em.createQuery(“select p from Person p where p.name=‘xiao’”); List result = query.getResultList(); Interator iterator = restult.iterator(); While(iterator.hasNext()){ … } //执行更新语句 Query query = em.createQuery(“update Person as p set p.name=?1 where p.personid=?2”); Query.setParameter(1,”黎明”); Query.setParameter(2,new Integer(1)); Int result = query.executeUpdate(); //影响的记录数 //执行更新语句 Query query = em.createQuery(“delete from Person”); Int result = query.executeUpdate(); //影响的记录数 执行SQL操作createNativeQuery() 【如果需要执行SQL语句,你可以使用此方法。注意,这里操作的是SQL语句而非JPQL】 @PersistenceContext protected EntityManager em; … //我们可以让EJB3 Persistence运行环境将列值直接填充如Entity,并将Entity作为结果放回。 Query query = em.createNativeQuery(“select * from person”,Person.class); List result = query.getResultList(); If(result != null){ Iterator iterator = result.iterator(); While(iterator.hasNext()){ Person person = (Person) iterator.next(); … } } //直接通过SQL执行更新语句 Query query = em.createNativeQuery(“update person set age = age + 2”); Qyery.executeUpdate();