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>

  

 

 

原文地址:https://www.cnblogs.com/lbblog/p/4753141.html