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>