六、hibernate中利用注解实现对象与数据库的映射关系(替代xx.hbm.xml配置文件)

版权声明:本篇文章由IT_CREATE整理 https://blog.csdn.net/IT_CREATE/article/details/87439010

之前介绍的是通过xml配置文件对对象和数据库之间的映射关系进行的绑定,这个方式太繁琐,需要写很多的配置文件。

下面就介绍结合注解如何完成在hibernate中对象与数据库之间的映射关系。这一版依然没有将hibernate和spring整合在一起,但不影响注解的使用关系。

所谓整合,就是将hibernate.cfg.xml配置文件和applicationContext.xml配置文件两个的配置整合到applicationContext.xml配置文件中,也就是通过配置spring的配置文件将持久层配置整合到spring容器中。

如何整合:请看https://blog.csdn.net/IT_CREATE/article/details/86141823

1、在maven项目中需要导入相关包

pom.xml配置文件:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.ge</groupId>
	<artifactId>hibernateanno</artifactId>
	<version>1.0</version>
	<packaging>jar</packaging>

	<name>hibernateanno</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<junit.version>4.12</junit.version>
		<log4j.version>1.2.17</log4j.version>
		<spring.version>4.3.14.RELEASE</spring.version>
		<hibernate.version>4.3.11.Final</hibernate.version>
		<mysql.version>5.1.38</mysql.version>
		<aspect.version>1.8.9</aspect.version>
	</properties>


	<dependencies>

		<!-- 引入第3方的切面框架AspectJrt的相关JAR文件 -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${aspect.version}</version>
		</dependency>

		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>${aspect.version}</version>
		</dependency>
		<!-- 导入spring容器相关JAR文件 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency>

		<!-- 导入hibernate持久层框架JAR包 -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<!-- 导入hibernate的二级缓存JAR包 -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-ehcache</artifactId>
			<version>${hibernate.version}</version>
		</dependency>


		<!-- 导入hibernate持久层框架的C3P0连接池JAR包 -->

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-c3p0</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<!-- 导入JDBC的JAR包 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.version}</version>
		</dependency>

	</dependencies>


	<build>
		<pluginManagement>

			<!-- 配置maven 在构建项目时,采用相关插件 -->
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.8.0</version>
					<configuration>
						<source>1.8</source>
						<target>1.8</target>
					</configuration>
				</plugin>


			</plugins>
		</pluginManagement>
	</build>

</project>

2、spring配置文件applicationContext.xml配置

applicationContext.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
						http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

	<!--开启自动扫描功能-->
	<context:component-scan base-package="com.ge.hibernateanno"></context:component-scan>

	<!-- 开启切面的动态代理支持 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

3、配置hibernate的数据库连接等基本信息

hibernate.cfg.xml配置文件:

<?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="dialect">
			org.hibernate.dialect.MySQLDialect
			<!-- org.hibernate.dialect.SQLServerDialect -->
			<!-- org.hibernate.dialect.OracleDialect -->
		</property>

		<!-- 配置JDBC连接数据库的4个最基本的元素 -->
		<property name="connection.driver_class">org.gjt.mm.mysql.Driver</property>
		<property name="connection.url">jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8</property>
		<property name="connection.username">root</property>
		<property name="connection.password">1234</property>

		<!-- 使用C3P0作为连接池技术 -->
		<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
		<!-- 配置C3P0连接池中,最大连接数为10 -->
		<property name="hibernate.c3p0.max_size">10</property>
		<!-- 指定连接池最小连接数 -->
		<property name="hibernate.c3p0.min_size">1</property>
		<!-- 指定连接池里连接超时时长 -->
		<property name="hibernate.c3p0.timeout">5000</property>
		<!-- 指定连接池里最大缓存多少个PreparedStatement对象 -->
		<property name="hibernate.c3p0.max_statements">100</property>
		<!-- 指定校验空闲连接的时间为:半分钟 -->
		<property name="hibernate.c3p0.idle_test_period">30000</property>
		<!-- 当连接不足时,需要再次获取的连接数量 -->
		<property name="hibernate.c3p0.acquire_increment">5</property>


		<!-- 手动开启hibernate的二级缓存技术 -->	
		<property name="hibernate.cache.use_second_level_cache">true</property>
		<!-- 配置二级缓存技术的提供类为ehcache中的EhCacheRegionFactory -->
		<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
		<!-- 开启二级缓存中的查询缓存 -->
		<property name="hibernate.cache.use_query_cache">true</property>
		
		
		

		<!--显示SQL语句 -->
		<property name="show_sql">true</property>
		<!--以格式良好的方式显示SQL语句 -->
		<property name="format_sql">true</property>

		<mapping class="com.ge.hibernateanno.bean.UserBean"/>
		<mapping class="com.ge.hibernateanno.bean.AddressBean"/>
		<mapping class="com.ge.hibernateanno.bean.UserInfoBean"/>
		<mapping class="com.ge.hibernateanno.bean.HusbandBean"/>
		<mapping class="com.ge.hibernateanno.bean.WifeBean"/>
		<mapping class="com.ge.hibernateanno.bean.StudentBean"/>
		<mapping class="com.ge.hibernateanno.bean.TeacherBean"/>
		<mapping class="com.ge.hibernateanno.bean.GameBean"/>
		<mapping class="com.ge.hibernateanno.bean.PlayerBean"/>
		
		<mapping class="com.ge.hibernateanno.bean.PetBean"/>
		<mapping class="com.ge.hibernateanno.bean.CatBean"/>
		<mapping class="com.ge.hibernateanno.bean.DogBean"/>

	</session-factory>

</hibernate-configuration>

4、因为本次用到了hibernate的二级缓存ehcache,所以要配置缓存

ehcache.xml配置文件:

<ehcache>
	<!-- 定义缓存数据存放的位置:java.io.tmpdir (默认为内存空间),如果要修改位置:/home/lilinhan/  d:/ehcache  -->
    <diskStore path="java.io.tmpdir"/>

	<!-- 定义默认的缓存配置 -->
    <defaultCache
    	
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        memoryStoreEvictionPolicy="LRU"
        />
        
        <!-- maxElementsInMemory="10000" 定义缓存中,可以存放数据的数据量 -->
        <!-- eternal="false" 设置存放的元素是否是"常量" -->
        <!-- timeToIdleSeconds="120" 设置元素在缓存空间中,不使用的情况下,默认的存活时间,单位是:秒 -->
        <!-- timeToLiveSeconds="120" 设置元素在缓存空间中,如果发生调用,需要重置的存活时间(只重置1次),单位是:秒 -->
        <!--  overflowToDisk="true" 当内存不足存储10000多个对象时,是否启动硬盘存储 -->
        <!-- memoryStoreEvictionPolicy="LRU" 设置缓存清理策略:LRU 最近最少使用    LFU 最少使用   FIFO 先进先出 -->

</ehcache>

下面开始介绍如何利用注解来替代之前的对象与数据库之间映射关系的xml配置文件。

1、单向关联

例如:有用户类,用户类中含有用户信息关联对象和地址信息关联对象(UserBean中包含了AddressBean、UserInfoBean)

UserBean.java类:

package com.ge.hibernateanno.bean;

import java.io.Serializable;
import java.util.Date;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Version;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.OptimisticLocking;



@Entity
@Table(name="t_user")
@OptimisticLocking(type=OptimisticLockType.VERSION)
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class UserBean implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = -1879857877221009050L;

	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="login_name",length=20)
	private String loginName;
	
	@Column(name="user_name",length=20)
	private String userName;
	
	@Column(name="user_pwd",length=32)
	private String password;
	
	@Column(name="age")
	private Integer age;
	
	@Column(name="gender")
	private Integer gender;
	
	@Column(name="birthday")
	private Date birthday;
	
	@Column(name="create_time")
	private Date createTime;
	
	@Version
	private Integer version;
	
	/**
	 * 人拥有人员信息,单向关联
	 */
	@OneToOne(fetch=FetchType.LAZY)
	@Cascade(value= {CascadeType.ALL})
	@JoinColumn(name="fk_info_id")
	private UserInfoBean userInfo;
	
	/**
	 * 人拥有多个地址,单向关联
	 */
	@OneToMany(fetch=FetchType.LAZY)
	@Cascade(value= {CascadeType.ALL})
	@JoinColumn(name="fk_user_id")
	@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
	private Set<AddressBean> adds;
	
	
	public UserBean() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	public UserBean(String loginName, String userName, Integer age) {
		super();
		this.loginName = loginName;
		this.userName = userName;
		this.age = age;
	}

	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getLoginName() {
		return loginName;
	}
	public void setLoginName(String loginName) {
		this.loginName = loginName;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Integer getGender() {
		return gender;
	}
	public void setGender(Integer gender) {
		this.gender = gender;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	public Date getCreateTime() {
		return createTime;
	}
	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}
	
	public UserInfoBean getUserInfo() {
		return userInfo;
	}

	public void setUserInfo(UserInfoBean userInfo) {
		this.userInfo = userInfo;
	}
	
	public Integer getVersion() {
		return version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	public Set<AddressBean> getAdds() {
		return adds;
	}

	public void setAdds(Set<AddressBean> adds) {
		this.adds = adds;
	}

	@Override
	public String toString() {
		return "UserBean [id=" + id + ", loginName=" + loginName + ", userName=" + userName + ", password=" + password
				+ ", age=" + age + ", gender=" + gender + ", birthday=" + birthday + ", createTime=" + createTime
				+ ", userInfo=" + userInfo + ", adds=" + adds + "]";
	}
}

@Entity 声明这个类是一个实体
@Table(name="t_user")  将对象与关联表联系起来
@OptimisticLocking(type=OptimisticLockType.VERSION) 声明版本控制,说明该表用到了版本控制来作为乐观锁
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE) 声明该类会用到缓存

关于版本控制和缓存如果没有,可以不用

@Id 声明此属性是id
@Column(name="id") 声明该属性与表中哪个字段对应
@GenericGenerator(name="hibernate.id",strategy="identity") 自定义主键生成策略,声明该id的增长规则,这里是按照表中自增长
@GeneratedValue(generator="hibernate.id") 绑定上面id增长规则的name

@Version声明该字段用于版本控制,与类上的@OptimisticLocking说明用到了版本控制呼应

@OneToOne(fetch=FetchType.LAZY)  声明一对一关系,用到懒加载的方式
@Cascade(value= {CascadeType.ALL})  声明级联操作,意思说我在查询用户的时候,把关联对象的属性一并查出来
@JoinColumn(name="fk_info_id") 声明该属性对应的表中哪个外键的字段

@OneToMany(fetch=FetchType.LAZY) 声明一对多关系,用到懒加载的方式
@Cascade(value= {CascadeType.ALL})  声明级联操作,意思说我在查询用户的时候,把关联对象的属性一并查出来
@JoinColumn(name="fk_user_id") 声明该属性对应的表中哪个外键的字段
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE) 声名该属性对应的关联对象是否也进行缓存,要实现关联对象也跟着缓存,那么关联对象的类上面也要@Cache实现缓存。

AddressBean.java类:

@Entity
@Table(name="t_address")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class AddressBean implements Serializable {

	private static final long serialVersionUID = 876189137233337215L;
	
	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="address",length=120)
	private String address;
	
	@Column(name="telphone",length=13)
	private String telphone;
}

UserInfoBean.java类:

@Entity
@Table(name="t_user_info")
public class UserInfoBean implements Serializable{

	private static final long serialVersionUID = -7547766667713260207L;
	
	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="idcard",length=18)
	private String idcard;
	
	@Column(name="job",length=20)
	private String job;
}

2、双向关联(一对一关系)

比如:丈夫和妻子(一个丈夫含有一个妻子,一个妻子含有一个丈夫)

HusbandBean.java类:

@Entity
@Table(name="t_hus")
public class HusbandBean implements Serializable {

	private static final long serialVersionUID = 3962071234349755981L;

	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="hus_name",length=20)
	private String husbandName;
	
	@Column(name="age")
	private Integer age;
	
	@OneToOne(fetch=FetchType.LAZY)
	@Cascade(value= {CascadeType.ALL})
	@JoinColumn(name="fk_wife_id")
	private WifeBean wife;
}

WifeBean.java类:

@Entity
@Table(name="t_wife")
public class WifeBean implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6156724853483253948L;

	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="wife_name",length=20)
	private String wifeName;
	
	@Column(name="age")
	private Integer age;
	
	/**
	 * mappedBy="wife" === xml中的 property-ref="wife" ,对应的是HusbandBean类中的wife这个属性,意思将控制权交给了HusbandBean
	 */
	@OneToOne(fetch=FetchType.LAZY,mappedBy="wife")
	@Cascade(value= {CascadeType.ALL})
	private HusbandBean hus;
}

3、双向关联(一对多关系)

这里用老师和学生进行举例(一个老师对应多个学生,一个学生对应一个老师)

TeacherBean.java类:

@Entity
@Table(name="t_teacher")
public class TeacherBean implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -878759933942301773L;

	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="teacher_name",length=20)
	private String teacherName;
	
	@Column(name="age")
	private Integer age;
	/**
	 * mappedBy="teacher"作用上面来讲: 等同于 inverse="true" 加  property-ref="teacher"
	 */
	@OneToMany(fetch=FetchType.LAZY,mappedBy="teacher")
	private Set<StudentBean> stus;
}

StudentBean.java类:

@Entity
@Table(name="t_student")
public class StudentBean implements Serializable {

	private static final long serialVersionUID = -7247391345977070063L;

	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="student_name",length=20)
	private String stuName;
	
	@Column(name="age")
	private Integer age;
	
	@ManyToOne(fetch=FetchType.LAZY)
	@Cascade(value= {CascadeType.SAVE_UPDATE})
	@JoinColumn(name="fk_teacher_id")
	private TeacherBean teacher;
}

4、双向关联(多对多关系)

这里用玩家和游戏进行说明(一个玩家可以选择多个游戏,一个游戏可以被多个玩家玩)

这里就需要涉及到一个中间表t_player_game:含有字段有id,fk_game_id,fk_player_id;通过这个中间表就可以找到t_player,t_game两个表之间的对应关系

PlayerBean.java类:

@Entity
@Table(name="t_player")
public class PlayerBean implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7432339810165709848L;
	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="player_name",length=20)
	private String playerName;
	
	
	@ManyToMany(fetch=FetchType.LAZY)
	@Cascade(value= {CascadeType.REFRESH})
	@JoinTable(name="t_player_game",joinColumns=@JoinColumn(name="fk_player_id"),
	inverseJoinColumns=@JoinColumn(name="fk_game_id"))
	private Set<GameBean> games;
}

GameBean.java类:

@Entity
@Table(name="t_game")
public class GameBean implements Serializable {


	private static final long serialVersionUID = -2921322568413358044L;

	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="game_name",length=20)
	private String gameName;
	
	/**
	 * mappedBy对应的是PlayerBean中的games,意思将控制权交给了PlayerBean
	 */
	@ManyToMany(fetch=FetchType.LAZY,mappedBy="games")
	private Set<PlayerBean> players;
}

5、继承关系

这里用宠物来说明(宠物中有狗和猫,狗和猫都继承宠物类)

PetBean.java类:

@Entity
@Table(name="t_pet")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="pet_type",discriminatorType=DiscriminatorType.STRING)
public class PetBean implements Serializable{

	private static final long serialVersionUID = 8563892643343101098L;
	
	@Id
	@Column(name="id")
	@GenericGenerator(name="hibernate.id",strategy="identity")
	@GeneratedValue(generator="hibernate.id")
	private Integer id;
	
	@Column(name="pet_name",length=20)
	private String petName;
}

继承映射在 Annotation 中使用 @Inheritance 注解,并且需要使用 strategy 属性指定继承策略,继承策略有 SINGLE_TABLE、TABLE_PER_CLASS 和 JOINED 三种。SINGLE_TABLE 是将父类和其所有的子类集合在一块,存在一张表中,并创建一个新的字段来判断对象的类型。

@DiscriminatorColumn指定表中那个字段用来作为鉴别

DogBean.java类:(继承PetBean)

@Entity
@DiscriminatorValue(value="0")
public class DogBean extends PetBean {

	private static final long serialVersionUID = -2609512928774812010L;
	
	@Column
	private Integer bone;
}

@DiscriminatorValue(value="0") 指定该类在鉴别字段的值

CatBean.java类:

@Entity
@DiscriminatorValue(value="1")
public class CatBean extends PetBean {

	private static final long serialVersionUID = -2501107672934091757L;

	@Column
	private int fish;
}

猜你喜欢

转载自blog.csdn.net/IT_CREATE/article/details/87439010