学框架,配置都是不可少的,有了配置,框架才知道我们想做什么,才知道如何去执行我们需要的操作!
hibernate的配置文件,总体来说分为两个部分:
1.主配置文件hibernate.cfg.xml文件,一般放在classpatn路径下
2.映射文件xxx.hbm.xml文件,一般跟实体类放在同一个包下
前者是配置相关的数据库以及引入的映射文件信息,而后者则主要配置对象与表之间的映射关系;
注意:配置文件的路径,因人而异,有的将映射文件集体放置在一起也有,所以看个人喜好,没有强制规定如何存放。
以下是hibernate.cfg.xml文件配置信息,为了方便记忆,我们将该配置文件内的配置信息分为三类:
1.数据库信息:方言、url、用户名、密码、数据库驱动,以<property>标签来配置
2.映射文件信息:即对象与表间的映射关系,以<mapping>标签来配置
3.其它配置信息:是否显示sql语句,格式化sql,二级缓存配置等等,以<property>标签来配置
<!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 name="foo"> <!-- 配置数据库信息 --> <!-- 配置数据库方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 配置数据库url --> <property name="connection.url">jdbc:mysql:///hibernate</property> <!-- 配置数据库驱动(mysql) --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 配置数据库用户名 --> <property name="connection.username">root</property> <!-- 配置数据库密码 --> <property name="hibernate.connection.password">1208</property> <!-- 是否显示sql --> <property name="hibernate.show_sql">true</property> <!-- 导入映射文件 该文件就是实体与数据库表之间的对应关系--> <mapping resource="com/hibernate/User.hbm.xml"/> </session-factory> </hibernate-configuration>
以下是映射文件基础配置,基础配置相对简单,后续还有关联配置、集合配置、通过注解配置等等:
为方便记忆,基础配置分为以下几类:
1.由于配置文件是配置对象与表之间的关系,所以必须配置对应的实体所在的包路径,以<hibernate-mapping>标签来配置;
2.接着开始配置实体与表之间的关系,使用<class>标签配置,通过name属性配置实体名,通过table属性配置表名;
3.理论上,每个表都应该设置一个主键,所以应该配置主键id,使用<id>标签进行配置;
4.实体的属性与表的列名对应,使用<property>进行配置;
以下面的基础配置代码为准:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- 实体类包路径 --> <hibernate-mapping package="com.hibernate"> <!-- 实体的名称、对应表名 --> <class name="User" table="sys_user"> <!-- 主键id、主键id类型、在表中的列名 --> <id name="id" type="int" column="id"> <!-- 自动增长 --> <generator class="native"/> </id> <!-- 实体属性名、实体属性类型、在表中的列名 --> <property name="name" type="string" column="name" length="20"/> </class> </hibernate-mapping>
主键属性(以<id>标签配置)配置说明:
主键属性,使用<id>标签进行配置,这里需要注意的是表中主键对应的对象属性最好使用包装类来修饰,例如表中的主键名为id,相对应的对象中的属性(假设也叫id)最好这么声明private Integer id;原因为如果使用private int id进行声明,那么id的初始值为0,如果以Integer对id进行声明,那么初始值为null,如果id为null表示与数据库中的表数据并没有对应关系即数据库并不存在该条数据。
子元素以<generator>标签配置,是用于主键生成策略的,常用的值有:
assigned:代表手工指定id,意思为向表中插入数据时,必须指定id值;
native:根据底层数据库的能力,选择identity、sequence、hilo中的一个;
identity:使用数据库的主键生成策略,注意不是所有的数据库都支持自动增长策略的;
sequence:在DB2、oracle、postgreSQL中使用此策略;
increment:查询表中id的最大值,然后由hibernate维护+1,不过不推荐使用,因为在多线程下会有问题;
uuid:由hibernate自动生成UUID,并指定为主键值,生成的值例如:4DEHS4523232JDKALDAJKLFDKAJ(类似);
hilo:按照高地位算法生成主键值,需要做以下配置
<generator class="hilo">
<param name="table">htbl</param>
<param name="column">next_value</param>
<param name="max_lo">100</param>
</generator>
htbl表只有一个字段next_value,该字段用来记录sys_user表插入了几次数据,max_lo属性用来设置每次增长的数据值,例如执行插入sys_user表数据第一次,那么htbl的next_value值就更新为1,sys_user表中的id值也为1,再次执行插入sys_user表,那么htbl的next_value值就更新为2,此时sys_user表中插入数据,这时插入的数据的行id变为101,从插入的第二次开始,sys_user的行id就通过属性max_lo来控制。该策略的优点是只需要额外的一张表,并且所有的数据都支持。
总结:一般使用native,配置数据库的时候就不需要修改该值。但具体的还是看情况,例如使用oracle,我们很清楚主键策略使用sequence,那就直接配置为sequence。
普通属性(非<id>标签配置,指以<property>配置)配置说明:
name属性:对象的名称或对象属性的名称,必须要有;
type属性:表示类型,如果不写,hibernate会自动检测,可以写java中类的全名或者写hibernate的类型,个人习惯是写hibernate类型,如字符串类型为string,数字类型为int,日期类型为date等等,可以参考下方的映射类型对照表和日期类型对照表;
column属性:对应表中的列名,如果没有,则默认为属性名,但是注意,如果属性名和表中的关键字重名了,这时候还是必须指定column属性,例如<property name="desc"/>如果默认属性名,那么执行程序会报错,因为desc和sql的排序关键字desc重名了,那么我们可以添加属性为column="desc_",如果一定要使用desc为列名,那么修改column属性为column=" ‘desc‘ ";
length属性:长度,不是所有的类型都有长度属性,比如varchar有,但是int就没有;
not-null属性:非空约束,默认为false
注意:如果实体中存在二进制属性,例如private byte[] photo,那么hbm文件中必须配置为
<property name="photo" type="binary" length="102400" column="photo"/>
以上是二进制属性在hibernate中的映射文件中的配置方法
java类型 | Hibernate映射类型 | SQL类型 |
java.math.BigDecimal | big_decimal | numeric |
byte[] | binary | varbinary(blob) |
boolean(java.lang.Boolean) | boolean | bit |
byte(java.lang.Byte) | byte | tinyint |
java.util.Calendar | calendar | timestamp |
java.sql.Clob | clob | clob |
java.util.Date 或java.sql.Date | date | date |
double(java.lang.Double) | double | double |
float(java.lang.Float) | float | float |
int (java.lang.Integer) | integer | integer |
java.util.Local | local | varchar |
long(java.lang.Long) | long | bigint |
java.io.Serializable的某个实例 | serializable | varbinary(或blob) |
java.lang.String | string | varchar |
java.lang.String | text | clob |
java.util.Date 或 java.sql.Timestamp | time | timestamp |
Java日期和时间类型的Hibernate映射类型
映 射 类 型 |
Java类型 |
标准SQL类型 |
描 述 |
date |
java.util.Date或者java.sql.Date |
DATE |
代表日期,形式为: YYYY-MM-DD |
time |
java.util.Date或者java.sql.Time |
TIME |
代表时间,形式为: HH:MM:SS |
timestamp |
java.util.Date或者java.sql. Timestamp |
TIMESTAMP |
代表时间和日期, 形式为: YYYYMMDDHHMMSS |
calendar |
java.util.Calendar |
TIMESTAMP |
同上 |
calendar_date |
java.util.Calendar |
DATE |
代表日期,形式为: YYYY-MM-DD |
这些实体与表映射关系配置信息,可以在表创建好之前配置,也可以在表创建后配置,什么意思?
这意味着我们可以不需要去创建表。当然,不想去创建表,还得需要配置,让hibernate帮我们去数据库创建表(自动帮我们生成表结构),在hibernate.cfg.xml文件内,在我们所谓的其他配置区域,配置上<property name="hbm2ddl.auto">create</property>,这样当运行程序,hibernate自动根据映射文件配置的表信息,去数据库创建表结构。
但是需要注意的是,配置该信息,每次执行程序后,hibernate会帮我们先去数据库查找是否存在该表,如果存在则删除再创建,如果不存在则直接创建表,缺点是并不会保留数据库表信息,每次执行程序后表都会被删除然后重新创建。
如果想避免这种情况,则将上述配置改为<property name="hbm2ddl.auto">update</property>,如此配置,当执行程序后,hibernate表不存在,则创建;发现表存在,并不删除表,只是则按照程序,更新数据。
还有一种配置,适合测试的时候用,即<property name="hbm2ddl.auto">create-drop</property>,如此配置,即初始化时创建表(程序启动),在session工厂(SessionFactory)执行close方法时,删除该表。
另外,该属性最后一种配置,即<property name="hbm2ddl.auto">validator</property>,这种配置在开发环境一般都不用,一旦hibernate发现hbm映射文件与数据库中表结构不一样,会抛出异常,开发中,表结构不随意更改,所以一般不使用该配置。
但是:总的来说,开发中,一般表结构我们都会事先创建好,一般都是使用脚本命令直接执行脚本,所以上述所谓"懒人建表"方法个人觉得适合学习用。
与hbm映射文件相关的持久化对象:
映射文件配置着对象与表间的对应关系,所以hibernate对持久化对象也是有要求的
1.持久化对象必须有无参构造器
例如:查询表中第一个用户,使用User对象来接收数据,User u = session.get(User.class,1);这时hibernate会通过反射帮我们创建一个User对象,然后再把数据塞进该对象,所以如果对象没有无参构造器,hibernate就没办法帮我们创建一个实体实例了。
2.提供一个标识的属性(通常映射为表的主键字段)
3.提供属性的get/set方法
***以上3点是必须做的事项***
4.不能给持久化对象设置final,这样导致该对象不能被继承,即最终类,会影响hibernate的懒加载功能,这个后续说,但是没什么需求会给对象设置final
5.如果需要把持久化对象放入到set中,当需要进行关联映射时,持久化对象需要重写equals和hashcode方法