JPA 注解
JPA注解
题要:jpa类似于JDBC,是jdk5.0之后提出的一种持久化单元规划,便于统一管理项目实体类,相对于hibernate中的xxx.hbm.xml要方便快捷许多,当然,如果要你去维护这样一个项目,还是很伤脑筋,同时,它没有索引,缓存,uuid等,除非你用hibernate的jpa,但是这样会和hibernate耦合,如果是缺省还好,属性太多不便于代码阅读,所以根据需求选择,javax.persistence是它提供的接口,实现由各厂商实现,就像JDBC有mysql,oracle提供的不同驱动一样,如hibernate,哦,对了,他们是同一个作者,所以许多地方类似,所以它有三个作用,1,实体--关系表映射,2,持久化,3,查询,所以你可以像在hibernate中配置hibernate.cfg.xml一样配置persistence.xml,可以向hibernate获取配置文件,获取类似sessionFatory,session一样,然后去做crud操作,当然你需要导入hibernate的一些包,就像导入mysql驱动一样,但是你可以不调用org.hibernate,当然,一般我们只会使用它的第一个功能实体--关系表映射,剩下两个交给hibernate去做,但是,我们导入的会是javax.persistence,而不是org.hibernate.
1、@Entity(name="EntityName")
必须,name为可选,对应数据库中一的个表
2、@Table(name="",catalog="",schema="")
可选,通常和@Entity配合使用,只能标注在实体的class定义处,表示实体对应的数据库表的信息
name:可选,表示表的名称.默认地,表名和实体名称一致,只有在不一致的情况下才需要指定表名
catalog:可选,表示Catalog名称,默认为Catalog("").
schema:可选,表示Schema名称,默认为Schema("").
3、@id
必须
@id定义了映射到数据库表的主键的属性,一个实体只能有一个属性被映射为主键.置于getXxxx()前.
4、@GeneratedValue(strategy=GenerationType,generator="")
可选
strategy:表示主键生成策略,有AUTO,INDENTITY,SEQUENCE 和 TABLE 4种,分别表示让ORM框架自动选择,
根据数据库的Identity字段生成(mysql),根据数据库表的Sequence字段生成(oracle),以有根据一个额外的表生成主键(速度太慢),默认为AUTO(一般使用它)
generator:表示主键生成器的名称,这个属性通常和ORM框架相关,例如,Hibernate可以指定uuid等主键生成方式.
示例:
@Id
@GeneratedValues(strategy=StrategyType.SEQUENCE)
public int getPk() {
return pk;
}
5、@Basic(fetch=FetchType,optional=true)
可选
@Basic表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的getXxxx()方法,默认即为@Basic
fetch: 表示该属性的读取策略,有EAGER和LAZY两种,分别表示主支抓取和延迟加载,默认为EAGER.
optional:表示该属性是否允许为null,默认为true
示例:
@Basic(optional=false)
public String getAddress() {
return address;
}
6、@Column
可选
@Column描述了数据库表中该字段的详细定义,这对于根据JPA注解生成数据库表结构的工具非常有作用.
name:表示数据库表中该字段的名称,默认情形属性名称一致
nullable:表示该字段是否允许为null,默认为true
unique:表示该字段是否是唯一标识,默认为false
length:表示该字段的大小,仅对String类型的字段有效
insertable:表示在ORM框架执行插入操作时,该字段是否应出现INSETRT语句中,默认为true
updateable:表示在ORM框架执行更新操作时,该字段是否应该出现在UPDATE语句中,默认为true.对于一经创建就不可以更改的字段,该属性非常有用,如对于birthday字段.
columnDefinition:表示该字段在数据库中的实际类型.通常ORM框架可以根据属性类型自动判断数据库中字段的类型,但是对于Date类型仍无法确定数据库中字段类型究竟是DATE,TIME还是TIMESTAMP.此外,String的默认映射类型为VARCHAR,如果要将String类型映射到特定数据库的BLOB或TEXT字段类型,该属性非常有用.
示例:
@Column(name="BIRTH",nullable="false",columnDefinition="DATE")
public String getBithday() {
return birthday;
}
7、@Transient
可选
@Transient表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性.
如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则,ORM框架默认其注解为@Basic
示例:
//根据birth计算出age属性
@Transient
public int getAge() {
return getYear(new Date()) - getYear(birth);
}
8、双向一对一
注:在双向关系时,多的一端是关系维护端,如果是一对一或者多对多,则是根据需求指定,即有外键的一端@JoinColumn(name="idcard_id"),它能记录外键的更改记录,但是不能自己更改外键
因一端则是被维护端,mappedBy="idCard"指定外键,类似配置文件中的<set name="order" inverse=true>
//inverse为false本端能维护关系
//inverse为true本端不能维护关系,交给另一端维护
package com.platform_easyuiSSH.hibernate.po; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; @Entity public class User { private Integer id; private String name; private IDCard idCard; public User(){} public User(String name){ this.name=name; } @OneToOne(cascade=CascadeType.ALL) @JoinColumn(name="idcard_id")//外键在关系维护端定义 public IDCard getIdCard() { return idCard; } public void setIdCard(IDCard idCard) { this.idCard = idCard; } @Id@GeneratedValue public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(length=20,nullable=false) public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.platform_easyuiSSH.hibernate.po; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToOne; @Entity public class IDCard { private Integer id; private String cardno; private User user; @OneToOne(mappedBy="idCard",cascade={CascadeType.REFRESH,CascadeType.MERGE},optional=false) public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Id@GeneratedValue public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(length=18,nullable=false) public String getCardno() { return cardno; } public void setCardno(String cardno) { this.cardno = cardno; } }
9,双向多对一
package com.platform_easyuiSSH.hibernate.po; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; /** * 订单项 */ @Entity public class OrderItem { private Integer id; private String productName; private Float price; //在多对一或者一对多的关系中,多的一方为关系维护端,关系维护端负责记录外键的更新 //它是没有权利更新外键记录的 private Order order; //optional是否为空,false表示外键不能为空 @ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=false) @JoinColumn(name="order_id")//外键名称 public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } @Id@GeneratedValue public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(length=40,nullable=false) public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } @Column(nullable=false) public Float getPrice() { return price; } public void setPrice(Float price) { this.price = price; } }
package com.platform_easyuiSSH.hibernate.po; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; /** * 订单 */ @Entity @Table(name="orders") public class Order { private String orderId; private Float amount=0f;//订单总价钱 private Set<OrderItem> items = new HashSet<OrderItem>(); //那一端出现了mappedby,就是关系的被维护端 //相当于hibernate <set name="order" inverse=true> //inverse为false本端能维护关系 //inverse为true本端不能维护关系,交给另一端维护 @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="order") public Set<OrderItem> getItems() { return items; } public void setItems(Set<OrderItem> items) { this.items = items; } @Id@Column(length=12) public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; } @Column(nullable=false) public Float getAmount() { return amount; } public void setAmount(Float amount) { this.amount = amount; } public void addOrderItem(OrderItem orderItem){ orderItem.setOrder(this); this.items.add(orderItem); } }
10,双向多对多
package com.platform_easyuiSSH.hibernate.po; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; @Entity public class Student { private Integer id; private String name; private Set<Teacher> teacher = new HashSet<Teacher>(); @ManyToMany(cascade={CascadeType.ALL}) @JoinTable(name="student_teacher",inverseJoinColumns=@JoinColumn(name="teacher_id") ,joinColumns=@JoinColumn(name="student_id")) public Set<Teacher> getTeacher() { return teacher; } public void setTeacher(Set<Teacher> teacher) { this.teacher = teacher; } @Id@GeneratedValue public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(length=10,nullable=false) public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.platform_easyuiSSH.hibernate.po; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToMany; @Entity public class Teacher { private Integer id; private String name; private Set<Student> student = new HashSet<Student>(); @ManyToMany(cascade=CascadeType.REFRESH,mappedBy="teacher") public Set<Student> getStudent() { return student; } public void setStudent(Set<Student> student) { this.student = student; } @Id@GeneratedValue public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(length=10,nullable=false) public String getName() { return name; } public void setName(String name) { this.name = name; } }
11,联合主键
package com.platform_easyuiSSH.hibernate.po; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Embeddable; /** * 联合主键的规则 * 1,实现序列化接口 * 2,提供一个无参的构造函数 */ @Embeddable//@Embeddable标示这个实体对象中的字段是联合主键的字段 public class AirLinePK implements Serializable{ private static final long serialVersionUID = -5417401022967854372L; private String startCity; private String endCity; public AirLinePK(){} @Column(length=3) public String getStartCity() { return startCity; } public void setStartCity(String startCity) { this.startCity = startCity; } @Column(length=3) public String getEndCity() { return endCity; } public void setEndCity(String endCity) { this.endCity = endCity; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((endCity == null) ? 0 : endCity.hashCode()); result = prime * result + ((startCity == null) ? 0 : startCity.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; AirLinePK other = (AirLinePK) obj; if (endCity == null) { if (other.endCity != null) return false; } else if (!endCity.equals(other.endCity)) return false; if (startCity == null) { if (other.startCity != null) return false; } else if (!startCity.equals(other.startCity)) return false; return true; } }
package com.platform_easyuiSSH.hibernate.po; import javax.persistence.Column; import javax.persistence.EmbeddedId; import javax.persistence.Entity; @Entity public class AirLine { private AirLinePK id; private String name; @EmbeddedId//@EmbeddedId标示这个属性是实体标识符 public AirLinePK getId() { return id; } public void setId(AirLinePK id) { this.id = id; } @Column(length=20) public String getName() { return name; } public void setName(String name) { this.name = name; } }
12,自定义annotation
package com.platform_easyuiSSH.hibernate.util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * 自定义annotation */ //定义属性,FIELD表示字段也可以使用 //method方法中可以获取,默认类,方法,字段等都可以使用 //@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME)//表示运行时也可以获取,SOURCE表示源码可以获取 public @interface HelloWorld { public String name() default "hello"; }
package com.platform_easyuiSSH.hibernate.util; import java.lang.reflect.Method; /** * 解析annotation */ public class Parser { public void parse(Object obj,String methodName){ Method[] ms = obj.getClass().getMethods(); for(Method m : ms){ if(m.getName().equals(methodName)){ if(m.isAnnotationPresent(HelloWorld.class)){ HelloWorld hw = m.getAnnotation(HelloWorld.class); System.out.println(hw.name()); try { System.out.println(hw.name()+"....before...."); m.invoke(obj, new Object[]{}); System.out.println(hw.name()+"....after...."); } catch (Exception e) { e.printStackTrace(); } } } } } }
package com.platform_easyuiSSH.hibernate.util; public class TestBean { //如果是value,可以这样@HelloWorld("你好") @HelloWorld private String name; public TestBean(String name){ this.name = name; } public TestBean(){} @HelloWorld public String getName() { return name; } public void setName(String name) { this.name = name; } @Override @HelloWorld(name="你好!!!") public String toString() { System.out.println(this.name); return this.name; } }
@Test public void beanTest(){ //自定义annotation TestBean tb = new TestBean("asdasd"); Parser parser = new Parser(); parser.parse(tb,"toString"); }
13,hibernate的配置文件
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.url"> jdbc:mysql://localhost:3306/test </property> <property name="connection.username">root</property> <property name="connection.password">admin</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 属性 --> <property name="show_sql">true</property> <property name="format_sql">true</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- hibernate实体建模 属性create会遍历配置文件中所有实体,删除创建,慎用 --> <!-- update和数据库表不匹配就更新 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- sessionFactory.getCurrentSession()从上下文中获取session,没有创建最新的 --> <!-- 属性主要有jta,在分布式多个数据库提交事务,thread线程 --> <!-- <property name="current_session_context_class">thread</property> --> <!-- 数据连接池配置,默认使用C3P0--> <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> <!-- 最大连接数 --> <property name="hibernate.c3p0.max_size">10</property> <!-- 最小连接数 --> <property name="hibernate.c3p0.min_size">5</property> <!-- 获得连接的超时时间,如果超过这个时间,会抛出异常,单位毫秒 --> <property name="hibernate.c3p0.timeout">120</property> <!-- 最大的PreparedStatement的数量 --> <property name="hibernate.c3p0.max_statements">30</property> <!-- 每隔120秒检查连接池里的空闲连接 ,单位是秒 --> <property name="hibernate.c3p0.idle_test_period">120</property> <!-- 当连接池里面的连接用完的时候,C3P0一下获取的新的连接数 --> <property name="hibernate.c3p0.acquire_increment">2</property> <!-- 开启二级缓存 --> <property name="hibernate.cache.use_second_level_cache">true</property> <!-- 指定缓存提供商 --> <property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <!-- 指定那些类缓存 --> <!-- 在po映射文件中指定<cache usage="read-only"/> --> <!-- 产生统计数据 --> <!-- 映射信息 --> <mapping resource="com/platform_easyuiSSH/hibernate/po/InfoTeacher.hbm.xml"/> <mapping resource="com/platform_easyuiSSH/hibernate/po/StuInfo.hbm.xml"/> <mapping resource="com/platform_easyuiSSH/hibernate/po/ClassInfo.hbm.xml"/> <!-- 使用annotation配置实体 --> <mapping class="com.platform_easyuiSSH.hibernate.po.JoinTeacher"/> <mapping class="com.platform_easyuiSSH.hibernate.po.Person"/> <!-- 一对多双向 --> <mapping class="com.platform_easyuiSSH.hibernate.po.Order"/> <mapping class="com.platform_easyuiSSH.hibernate.po.OrderItem"/> <!-- 一对一双向 --> <mapping class="com.platform_easyuiSSH.hibernate.po.IDCard"/> <mapping class="com.platform_easyuiSSH.hibernate.po.User"/> <!-- 多对多双向 --> <mapping class="com.platform_easyuiSSH.hibernate.po.Teacher"/> <mapping class="com.platform_easyuiSSH.hibernate.po.Student"/> <!-- 联合主键 --> <mapping class="com.platform_easyuiSSH.hibernate.po.AirLine"/> <!-- 配置二级缓存类 --> <class-cache usage="read-only" class="com.platform_easyuiSSH.hibernate.po.InfoTeacher"/> </session-factory> </hibernate-configuration>
hibernate4.0后针对c3p0和二级缓存导入的依赖
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
</dependency>
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.platform_easyuiSSH.hibernate.po"> <class name="ClassInfo" table="classinfo"> <id name="c_id" column="c_id"> <generator class="increment"></generator> </id> <property name="c_name" column="c_name"></property> <!-- lazy = false 不延迟 会把字表数据查出 --> <!-- lazy = true 延迟 需要字表数据才会查出,但是session不能关闭--> <set name="stu_set" table="stuinfo" order-by="s_id" lazy="false" cascade="all"> <key column="c_id"></key> <one-to-many class="com.platform_easyuiSSH.hibernate.po.StuInfo"/> </set> </class> </hibernate-mapping> <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.platform_easyuiSSH.hibernate.po"> <class name="StuInfo" table="stuinfo"> <id name="s_id" column="s_id"> <generator class="increment"></generator> </id> <property name="s_name" column="s_name"></property> <property name="c_id" column="c_id"></property> </class> </hibernate-mapping>
14,ehcache.xml的配置文件,放在项目根目录下可以被hibernate自动找到
<?xml version="1.0" encoding="UTF-8"?> <ehcache> <!--timeToIdleSeconds 当缓存闲置n秒后销毁 --> <!--timeToLiveSeconds 当缓存存活n秒后销毁 --> <!-- 缓存配置 name:缓存名称。 maxElementsInMemory:缓存最大个数。 eternal:对象是否永久有效,一但设置了,timeout将不起作用。 timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。 timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。 overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 maxElementsOnDisk:硬盘最大缓存个数。 diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false. diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 clearOnFlush:内存数量最大时是否清除。 --> <!--如果缓存中的对象存储超过指定的缓存数量的对象存储的磁盘地址--> <diskStore path="java.io.tmpdir" /> <!-- 默认cache:如果没有对应的特定区域的缓存,就使用默认缓存 --> <defaultCache maxElementsInMemory="500" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="1200" overflowToDisk="true" /> <!-- 指定区域cache:通过name指定,name对应到Hibernate中的区域名即可--> <cache name="com.Menu" maxElementsInMemory="150" eternal="false" timeToLiveSeconds="36000" timeToIdleSeconds="3600" overflowToDisk="true"/> </ehcache>