kamhung的专栏

一个用毛笔写程序的程序员

用户操作
[即时聊天] [发私信] [加为好友]
zhang ID:kamhung
1181次访问,排名2万外好友0人,关注者0
kamhung的文章
原创 2 篇
翻译 0 篇
转载 0 篇
评论 24 篇
最近评论
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 在Java SE环境下使用JPA1.0(Java EE 5.0 中的主要组成部分)收藏

    新一篇: 常见J2ME系统属性及其作用列表 | 

           
           Java Persistence API 1.0( EJB3 Entity Bean) 在Java EE5中, Entity Bean做为EJB规范中负责持久化的组件将逐渐成为一个历史名词了,作为J2EE 4规范中最为人所垢病的Entity Bean在Java EE5中被推到重来,取而代之的是java开发的通用持久化规范Java Persistence API 1.0。JPA作为java中负责关系数据持久化的组件已经完全独立出来成为一个单独的规范,而不再属于Enterprise Java Bean的范畴。

          Java Persistence AP(JPA)可以说是java持久化技术的一个集大成者,它吸取了Hiberante,JDO,TopLink等优秀技术和框架,将这几年发展成熟起来的基于POJO模型的O/R Mapping技术标准化,成为在J2EE和J2SE环境中通用的java持久化API。值得注意的是Java Persistence API并不是J2EE环境专用,而是在java中的通用API。意味着我们可以在任何需要访问关系数据库的地方使用JPA,甚至包括swing开发的桌面应用。JPA也不要求一定在J2EE容器中才能运行,而是任何有JVM的环境都可以运用。这就使得我们可以很容易的把JPA作为一个持久化组件自由地和各种容器/框架(EJB3容器, Spring等等)组合。

    下面是我做的一个JPA 在 Java SE 环境下的使用范例.

    一、搭建环境

    1)   搭建数据库环境

       1、安装数据库(MySQL 5.0.24), 用户: root,密码: (空) 。
       2、建库piscesdb。
       3、建表address:
           
    drop table address;

    create table address (
       addressID 
    int not null,
       city 
    varchar(55not null,
       street 
    varchar(55NOT NULL,
       zip 
    varchar(8NOT NULL,
       
    PRIMARY KEY  (addressID)
    );

    insert into address values (1, "深圳", "坂田市场", "518001");
    insert into address values (2, "深圳", "坂田路口", "518002");
    insert into address values (3, "深圳", "四季花城", "518003");

      4、建表userinfo:
          
    drop table userinfo;

    create table userinfo (
       userID 
    int not null,  /** 用户id  */
       username 
    varchar(20not null/** 姓名  */
       birthday 
    datetime null,   /**  出生日期  */
       sex 
    varchar(8not null,   /** 性别 */
       addressID 
    int not null,    /** 地址id  */
       
    PRIMARY KEY (userID)
    );

    insert into userinfo values (1, "张先生", null, "male", 1);
    insert into userinfo values (2, "李某某", null, "male", 2);
    insert into userinfo values (3, "王某某", '2006-08-10', "female", 3);
    insert into userinfo values (4, "陈某某", '2006-08-12', "male", 3);



    2)   获取额外的jar包

        下载JPA的实现类, 去https://glassfish.dev.java.net/downloads/persistence/JavaPersistence.html下载GlassFish v1 FCS branch版本,
    进行安装后得到toplink-essentials.jar,toplink-essentials-agent.jar 两个包,将这两个包和mysql的驱动包加入到项目的classpath路径中去。
    编译
    toplink源码需要 javax.transaction、org.apache.tools.ant 两个包
    项目工程路径不要含中文, 因为 toplink 暂时不支持。

    3)   开发环境

      JDK:  jdk 6.0 beta2 (JDK 5.0 也可以)
       IDE:  NetBeans 5.0 中文版

    二、开发

    1)   创建实体Entity类

       1、地址类 Address :
     
    /*
     * Address.java
     
    */

    package org.pisces.persist;

    import java.io.Serializable;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Id;

    /**
     *
     * 
    @author kamhung
     
    */
    @Entity 
    public class Address implements Serializable {
        
    //地址id, 不能为空, 必须唯一
        @Id 
        @Column(name 
    = "addressid", unique=true, nullable=false)
        
    private int addressid;
        
        
    //城市, 不能为空
        @Column(name = "city", nullable=false)
        
    private String city;
        
        
    //街道, 不能为空
        @Column(name = "street", nullable=false)
        
    private String street;
        
        
    //邮政编码, 不能为空
        @Column(name = "zip", nullable=false)
        
    private String zip;
        
        
    public Address() {
        }
        
        
    public Address(int addressid) {
            
    this.setAddressid(addressid);
        }
        
        
    public int getAddressid() {
            
    return this.addressid;
        }
        
        
    public void setAddressid(int addressid) {
            
    this.addressid = addressid;
        }
        
        
    public String getCity() {
            
    return this.city;
        }
        
        
    public void setCity(String city) {
            
    this.city = city;
        }
        
        
    public String getStreet() {
            
    return street;
        }
        
        
    public void setStreet(String street) {
            
    this.street = street;
        }
        
        
    public String getZip() {
            
    return this.zip;
        }
        
        
    public void setZip(String zip) {
            
    this.zip = zip;
        }
        
        @Override
        
    public int hashCode() {
            
    return this.addressid;
        }
        
        @Override
        
    public boolean equals(Object object) {
            
    if (!(object instanceof Address)) return false;
            
    final Address other = (Address)object;
            
    return this.addressid == other.addressid;
        }
        
        @Override
        
    public String toString() {
            
    return "Address[addressid=" + getAddressid() + ", city='" + getCity() + "', street='" + getStreet() + "', zip='" + getZip() +"']";
        }
    }

       2、用户类 UserInfo:
    /*
     * UserInfo2.java
     
    */

    package org.pisces.persist;

    import java.io.Serializable;
    import java.sql.Timestamp;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.OneToOne;
    import static javax.persistence.CascadeType.*;

    /**
     *
     * 
    @author kamhung
     
    */
    @Entity 
    public class UserInfo implements Serializable {
        
    //用户id, 不能为空, 必须唯一
        @Id 
        @Column(name 
    = "userid", unique=true, nullable=false)
        
    private int userid;
        
        
    //用户名, 不能为空
        @Column(name = "userName", nullable=false)
        
    private String userName;
        
        
    //性别, 不能为空
        @Column(name = "sex", nullable=false)
        
    private String sex;
        
        
    //出生日期, 可以为空
        @Column(name = "birthday")
        
    private Timestamp birthday;
        
        
    //地址, 不能为空
        
    //PERSIST 表示更新、新增UserInfo数据时会同时更新、新增Address的数据
        
    //REMOVE 表示从数据库删除UserInfo会同时删除Address表中对应的数据
        @OneToOne(cascade={PERSIST, REMOVE})
        @JoinColumn(name 
    = "addressID", nullable=false)
        
    private Address address;
        
        
    public UserInfo() {
        }
        
        
    public UserInfo(int userid) {
            
    this.setUserid(userid);
        }
        
        @Override
        
    public int hashCode() {
            
    return this.getUserid();
        }
        
        @Override
        
    public boolean equals(Object object) {
            
    if (!(object instanceof UserInfo)) return false;
            
    final UserInfo other = (UserInfo)object;
            
    return this.userid == other.userid;
        }
        
        @Override
        
    public String toString() {
            
    return "UserInfo[userid=" + this.userid + ", userName='" + userName + "', sex='" + sex
                    
    + "', birthday=" + birthday + ", address=" + address + "]";
        }
        
        
    public int getUserid() {
            
    return userid;
        }
        
        
    public void setUserid(int userid) {
            
    this.userid = userid;
        }
        
        
    public String getUserName() {
            
    return userName;
        }
        
        
    public void setUserName(String userName) {
            
    this.userName = userName;
        }
        
        
    public Timestamp getBirthday() {
            
    return birthday;
        }
        
        
    public void setBirthday(Timestamp birthday) {
            
    this.birthday = birthday;
        }
        
        
    public String getSex() {
            
    return sex;
        }
        
        
    public void setSex(String sex) {
            
    this.sex = sex;
        }
        
        
    public Address getAddress() {
            
    return address;
        }
        
        
    public void setAddress(Address address) {
            
    this.address = address;
        }
    }


    2)   创建配置文件persistence.xml

           在项目src文件夹下创建一个META-INF文件夹(有就不用创建了), META-INF文件夹下建一个persistence.xml文件, 内容为:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="1.0" 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">
        
    <!-- transaction-type 可选值有: JTA、RESOURCE_LOCAL ;
        在Java EE 环境下默认值为JTA, 在Java SE 环境下默认值为RESOURCE_LOCAL;
        如果值为JTA的话, 则必须要指定<jta-data-source>的值 
    -->
        
    <persistence-unit name="piscesPU" transaction-type="RESOURCE_LOCAL">
            
    <description>这是piscesPU持久化单元的一个简单描述</description>
            
    <!-- 指明javax.persistence.spi.PersistenceProvider 的实现类, 一般来说该节点可以省略 -->
            
    <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
            
    <!-- 在Java SE环境下必须定义所有的实体Entity类, 也可以用 <mapping-file> 或<jar-file> 节点代替 -->
            
    <class>org.pisces.persist.UserInfo</class>
            
    <class>org.pisces.persist.Address</class>
            
    <!--
            //可以定义jndi资源代替properties节点中的数据库配置,
            //但是在调用Persistence.createEntityManagerFactory方法前必须保证此资源已经注入程序中.
            <jta-data-source>jdbc/persist</jta-data-source>
            
    -->  
     
            
    <!-- properties节点是用来定义各种JPA实现包所定义的属性配置 -->  
            
    <!-- 下面列举的是toplink实现包中可以配置的部分属性 -->
            
    <properties>            
                
    <!-- 数据库连接配置, JDBC驱动 -->
                
    <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/>  
                
    <!-- 数据库连接配置,URL -->
                
    <property name="toplink.jdbc.url" value="jdbc:mysql://localhost:3306/piscesdb"/>
                
    <!-- 数据库连接配置, 用户名 -->
                
    <property name="toplink.jdbc.user" value="root"/>
                
    <!-- 数据库连接配置, 密码 -->
                
    <property name="toplink.jdbc.password" value=""/>  
                
                
    <!-- 数据库连接池配置, 可写的连接池的最大连接数, 默认为 10 -->
                
    <property name="toplink.jdbc.write-connections.max" value="10"/>
                
    <!-- 数据库连接池配置, 可写的连接池的最大连接数, 默认为 5 -->
                
    <property name="toplink.jdbc.write-connections.min" value="5"/>
                
    <!-- 数据库连接池配置, 只读的连接池的最大连接数, 默认为 2 -->
                
    <property name="toplink.jdbc.read-connections.max" value="2"/>
                
    <!-- 数据库连接池配置, 只读的连接池的最大连接数, 默认为 2 -->
                
    <property name="toplink.jdbc.read-connections.min" value="2"/>
                
    <!-- 数据库连接池配置, 只读的连接池是否可以共享, 默认为 false -->
                
    <property name="toplink.jdbc.read-connections.shared" value="false"/>
                
    <!-- 是否绑定所有jdbc属性, 默认为 true -->
                
    <property name="toplink.jdbc.bind-parameters" value="true"/>
                
                
    <!-- 缓冲配置, 以下三个属性值为默认设置;
                 可以 default改为entity名(@Entity注释中的name属性值)或者类名来指定该entity的缓冲配置, 如:
                <property name="toplink.cache.size.org.pisces.persist.UserInfo" value="2"/>
                <property name="toplink.cache.type.org.pisces.persist.UserInfo" value="SoftWeak"/>
                <property name="toplink.cache.shared.org.pisces.persist.UserInfo" value="true"/>
                
    -->
                
    <property name="toplink.cache.size.org.pisces.persist.UserInfo" value="2"/>
                
    <!-- 缓冲配置, 缓冲大小, 默认为 1000 -->
                
    <property name="toplink.cache.size.default" value="1000"/>
                
    <!-- 缓冲配置, 缓冲类型, 可选值为{ Weak、SoftWeak、HardWeak、Full、NONE }, 不区分大小, 默认为 SoftWeak -->
                
    <property name="toplink.cache.type.default" value="SoftWeak"/>
                
    <!-- 缓冲配置, 是否共享缓冲, 默认为 false -->
                
    <property name="toplink.cache.shared.default" value="false"/>
                
                
    <!-- 日志配置, 日志级别, 默认值为java.util.logging.Level在系统中的值 -->
                
    <property name="toplink.logging.level" value="SEVERE"/>
                
    <!-- 日志配置, 日志是否记录当前时间, 默认为 true -->
                
    <property name="toplink.logging.timestamp" value="true"/>
                
    <!-- 日志配置, 日志是否记录当前线程名, 默认为 true -->
                
    <property name="toplink.logging.thread" value="true"/>
                
    <!-- 日志配置, 日志是否记录当前会话名, 默认为 true -->
                
    <property name="toplink.logging.session" value="true"/>
                
    <!-- 日志配置, 日志是否记录异常堆栈, 默认为 true -->
                
    <property name="toplink.logging.exceptions" value="true"/>
                
                
    <!-- 目标数据库类型, 截至目前为止可选值为{ Auto、Oracle、Attunity、Cloudscape、Database、DB2、DB2Mainframe
                 、 DBase、Derby、HSQL、Informix、JavaDB、MySQL4、PostgreSQL、SQLAnyWhere、 SQLServer、Sybase、TimesTen },
                 不区分大小, 默认为 Auto, 即 TopLink自动匹配对应的数据库类型 
    -->
                
    <property name="toplink.target-database" value="Auto"/>
                
                
    <!-- 指定会话名称, 默认为系统自动产生唯一性名称-->
                
    <property name="toplink.session-name" value="pisces_session_name"/>
                
                
    <!-- 设置是否为weaving, 默认为 true -->
                
    <property name="toplink.weaving" value="true"/>
                
                
    <!-- 指定目标应用服务器类型, 截至目前为止可选值为{ None、OC4J_10_1_3、SunAS9 }(以后可能会扩展其他值的),
                 在 Java SE环境下值为 None, 不区分大小, 默认为 None 
    -->
                
    <property name="toplink.target-server" value="None"/>
                            
                
    <!-- 指定实现 oracle.toplink.essentials.tools.sessionconfiguration.DescriptorCustomizer 的类名,
                 toplink.descriptor.customizer.  为前缀, 后面跟entity名(@Entity注释中的name属性值)或者entity类名,
                 该类中的customize方法在执行 了所有的属性(除了 toplink.session.customizer 之外)后运行, 如:
                <property name="toplink.descriptor.customizer.org.pisces.persist.UserInfo" value="org.pisces.persist.SimpleDescriptorCustomizer"/>
                <property name="toplink.descriptor.customizer.org.pisces.persist.Address" value="org.pisces.persist.SimpleDescriptorCustomizer"/>
                
    -->
                
    <!-- 指定实现 oracle.toplink.essentials.tools.sessionconfiguration.SessionCustomizer 的类名,
                该类中的customize方法在执行了所有的属性后运行, 如:
                <property name="toplink.session.customizer" value="org.pisces.persist.SimpleSessionCustomizer"/>
                
    -->
            
    </properties>
        
    </persistence-unit>
    </persistence>



    3)   创建Entity的管理类

           管理类SimpleManager是用来对实体Entity进行操作管理的.
    /*
     * SimpleManager.java
     
    */

    package org.pisces.persist;

    import java.util.List;
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;

    /**
     *
     * 
    @author kamhung
     
    */
    public class SimpleManager {
       
      
    //一个持久单元对应一个EntityManagerFactory
        private static final EntityManagerFactory emf =Persistence.createEntityManagerFactory("piscesPU");
        
        
    private SimpleManager(){
            
    //do nothing
        }
        
        
    /**
         * 删除用户id=6的数据
         
    */
        
    public static void delete() {
            
    final EntityManager em =emf.createEntityManager();
            
    //找不到数据的话这里会抛异常
            UserInfo info =em.find(UserInfo.class6);
            
    try {
                em.getTransaction().begin();
                em.remove(info);
                em.getTransaction().commit();
            } 
    finally {
                em.close();
            }
        }
        
        
    /**
         * 修改用户id=6的数据
         
    */
        
    public static void update() {
            
    final EntityManager em =emf.createEntityManager();
            
    //找不到数据的话这里会抛异常
            UserInfo info =em.find(UserInfo.class6);
            info.setUserName(
    "哈哈");
            info.getAddress().setStreet(
    "坂田2");
            
    try {
                em.getTransaction().begin();
                
    //自动将info更新到数据库
                em.getTransaction().commit();
            } 
    finally {
                em.close();
            }
        }
        
        
    /**
         * 查询所有用户数据
         
    */
        
    public static void query() {
            
    long s =System.currentTimeMillis();
            
    //数据库连接失败这里会抛出异常
            final EntityManager em =emf.createEntityManager();
            
    long e =System.currentTimeMillis();
            System.out.println(
    "连接数据库耗时: " + (e-s) + "毫秒" );
            
    //获取数据
            @SuppressWarnings("unchecked")
            List
    <UserInfo> list =em.createQuery("SELECT a FROM UserInfo a").getResultList();
            
    int i=0;
            
    for(UserInfo info : list) {
                System.out.println(
    "" + (++i) + "个值为: " + info);
            }
            em.close();
        }
        
        
    /**
         * 创建用户id=6的一条数据, 地址id=6
         
    */
        
    public static void create() {
            
    final EntityManager em =emf.createEntityManager();
            
            UserInfo info 
    =new UserInfo(6);
            info.setSex(
    "male");
            info.setUserName(
    "张某某");
            info.setBirthday(
    new java.sql.Timestamp(System.currentTimeMillis()));
            Address naddr 
    =new Address(6);
            naddr.setCity(
    "深圳");
            naddr.setStreet(
    "坂田");
            naddr.setZip(
    "518000");
            info.setAddress(naddr);
            
            
    try {
                em.getTransaction().begin();
                em.persist(info);
                em.getTransaction().commit();
            } 
    finally {
                em.close();
            }
        }
    }


    三、运行

       1、  编写main函数:
    /*
     * Main.java
     
    */

    package org.pisces;

    import org.pisces.persist.SimpleManager;

    /**
     *
     * 
    @author kamhung
     
    */
    public class Main {

        
    /**
         * 主函数
         
    */
        
    public static void main(String[] args) throws Throwable {
            SimpleManager.query();
            SimpleManager.create();
            System.out.println(
    " 新增一条数据后进行查询");
            SimpleManager.query();
            SimpleManager.update();
            System.out.println(
    " 修改一条数据后进行查询");
            SimpleManager.query();
            SimpleManager.delete();
            System.out.println(
    " 删除一条数据后进行查询");
            SimpleManager.query();
        }
    }
     
      2、 运行结果如下:
    run:
    连接数据库耗时: 1000毫秒
    第1个值为: UserInfo[userid
    =1, userName='先生', sex='male', birthday=null, address=Address[addressid=1, city='深圳', street='坂田市场', zip='518001