在hibernate的配置文件中出现了
<property name="password" type="java.lang.String">
<column name="password" length="45" not-null="true" />
</property>
表明当前的属性不允许为空,Hibernate在持久化给对象时,会检查password属性是否为NULL 如果为NULL 那么就会抛出下面的异常:
org.hibernate.PropertyValueException:not-null property refrences a null or transient value:包名.类名.属性名
如果数据库中的映射的字段时不允许为空,但配置文件中没有设置not-null 属性时:<column name="password" length="45" />
因此数据库会抛出错误:ERROR JDBCExceptionReporter:58 -General error,message from server:"Column 'password' cannot be null"
Hibernate配置文件-添加静态方法
<property name="username" type="java.lang.String">
<meta attribute="find-method">findByName</meta>
<column name="username" length="45" not-null="true" />
</property>
其中<meta>标签的find-method 选项用于设置find 的方法名,以上代码表明在某一个类中定义一个静态的方法叫:findByName(Session session,String username),该方法按照username属性到数据库中检索匹配的对象
Hibernate设置包名
<class>元素的name属性时必须提供完整的类名即,类所在的包的名字,如果在一个配置文件包含多个类,并且这些类都位于一个包中,每次都设定类的名字很烦,此时一下两中映射方式是等价的:
<hibernate-mapping package="com.entity">
<class name="User" table="UserInfo" catalog="demo">.....
<class name="Role" table="RolrInfo" catalog="demo">.....
</hibernate-mapping>
<hibernate-mapping>
<class name="org.entry.User" table="UserInfo" catalog="demo">
<class name="org.entry.Role" table="RolrInfo" catalog="demo">
</hibernate-mapping>
HIbernate的Ssession的commit()和flush()方法的区别:flush()方法进行清理缓存的操作,执行一系列的sql语句,打不会提交事物,commit()方法会先调用flush()方法,然后提交事物,提交事物意味着对数据库的所有操作将被永久保存下来
Betch procession批量处理
使用Hibernate将100000条记录插入到数据库中是一个很自然的做法可能是这样的:
Session session=sessionFactory.openSession();
Transaction tx= session.beginTransaction();
for (int i = 0; i < 100000; i++) {
User user=new User(.....);
session.save(user);
}
tx.commit();
session.close();
这个程序大概运行到50000行会出现内存溢出异常,这是因为Hibernate把所有的新插入的记录保存在session级别的缓存区进行缓存的原因
一般在使用时我们配置的jdbc批量抓取数量(bath size)是10-50之间
hibernate.jdbc.batch_size 20当然在执行批处理时关闭二级缓存:
hibernate.cache.use_second_level_cache false
批量插入(Batch inserts):
Session session=sessionFactory.openSession();
Transaction tx= session.beginTransaction();
for (int i = 0; i < 100000; i++) {
User user=new User(.....);
session.save(user);
if(i%20==0)
{
session.flush();
session.clear();
}
}
tx.commit();
session.close();
批量更新(Batch updates):
Session session=sessionFactory.openSession();
Transaction tx= session.beginTransaction();
String hql="select distinct s.billNumber,s.billDate,s.billState,s.department from StockRequisition as s";
命名查询
<hibernate-mapping>
<sql-query name="queryStaffBySex">
<![CDATA[update userInfo set sex=:sex where sex is null ]]>
<return alias="s" class="com.form.Staff"/>
</sql-query>
</hibernate-mapping>
ScrollableResults resluts=session.getNamedQuery("queryStaffBySex").setCacheMode(CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY);
int count=0;
while (resluts.next()) {
User user=(User)resluts.get(0);
user.setSex("男");
if(++count%20==0)
{
session.flush();
session.clear();
}
}
1 将整个继承关系放在一张表中,为了区分具体的子类信息,表中需要创建一个额外的列
create table paymeny(
.....
type varchar2(12)
);
<class name="Payment" table="payment">
.....
<discriminitor column="type" type="string">
<sub-class name="CardPayment" discriminitor-value="card">
子类属性
</sub-class>
<sub-class name="CashPayment" discriminitor-value="cash">
子类属性
</sub-class>
</class>
操作方便 效率较高 多态
冗余 浪费空间
2 将父类信息和每个子类信息结合在一起,创建多张具体的表
create table cardpayment(
父类信息
信用卡子类信息
)
create table cashpayment(
父类信息
现金子类信息
)
<class name="Payment">
.....
<union-sub-class name="CardPayment" table="cardpayment">
子类属性
</union-sub-class>
<union-sub-class name="CashPayment" table="cashpayment">
子类属性
</union-sub-class>
</class>
操作方便 效率较高 空间利用率较高
冗余 没有多态
3 针对每个具体的对象,创建其对应得表
create table payment(
父类信息
)
create table cardpayment(
信用卡子类信息
外键cardid
)
create table cashpayment(
现金子类信息
外键cashid
)
<class name="Payment" table="payment">
.....
<joined-sub-class name="CardPayment" table="cardpayment">
<key column="cardid"></key>
子类属性
</joined-sub-class>
<joined-sub-class name="CashPayment" table="cashpayment">
<key column="cashid"></key>
子类属性
</joined-sub-class>
</class>
多态 没有冗余 空间利用率较高
操作复杂 效率较低
hibernate查询:
1 native sql
程序员精通sql
自己控制sql的效率
查询到的信息只能自己封装
2 hql Student1 ----1 Address
在sql框架基础之上,面向对象
from Student;
select s.name from Student s;
from Student s where s.age > 20;
from Student s inner join address a where a.name=...;
3 criteria
标准面向对象式查询
session.createCriteria(Student.class);
session.createCriteria(Student.class)
.add(Restrictions.gt("age",20));
session.createCriteria(Student.class)
.createCriteria("address")
.add(Restrictions.eq("name","..."));
4 named query
将sql语句彻底从源代码中提取到映射文件中
*.hbm.xml
<hibernate-mapping>
<class>
.....
</class>
<query name="sql变量名">
<![CDATA[
hql语句... ?/:name
]]>
</query>
</hibernate-mapping>
session.getNamedQuery("sql变量名")
hibernate对数据源的支持:
1 hiebrnate内置数据源,仅用于测试
<property name="connection.username">scott</property>
<property name="connection.url">
jdbc:oracle:thin:@localhost:1521:sinojava
</property>
<property name="dialect">
org.hibernate.dialect.Oracle9Dialect
</property>
<property name="connection.password">tiger</property>
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
2******* hibernate整合c3p0*******
<property name="connection.username">scott</property>
<property name="connection.url">
jdbc:oracle:thin:@localhost:1521:sinojava
</property>
<property name="dialect">
org.hibernate.dialect.Oracle9Dialect
</property>
<property name="connection.password">tiger</property>
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
添加以下信息:
<property name="connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</property>
<property name="c3p0.max_size">5</property>
<property name="c3p0.timeout">2000</property>
..........
3 jndi
<property name="connection.username">scott</property>
<property name="connection.url">
jdbc:oracle:thin:@localhost:1521:sinojava
</property>
<property name="dialect">
org.hibernate.dialect.Oracle9Dialect
</property>
<property name="connection.password">tiger</property>
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
添加以下信息:
<property name="jndi">java:comp/env/userDs</property>
程序中必须手动获取连接,传递给hibernate:
getSession(){
Context env = new IntialContext();
DataSource ds = (DataSource)env.lookup("java:comp/env/userDs");
Conenction con = ds.getConnection();
...
sessionFactory.openSession(conn);
....
}
hibernate对于分页的支持:
query.setFirstResult(起始位置);
query.setMaxResults(查询条数);
query.list();
锁:
读锁/写锁
表级锁/列级锁
JDBC中的并发控制:
1 数据库
隔离级别
TRANSACTION_NONE 0
TRANSACTION_UNCOMMITED_READ 1
TRANSACTION_COMMIED_READ 2
TRANSACTION_REPEATABLE_READ 4
TRANSANTION_SERIALIZABLE 8
Connection.setTransactionIsolation(...)
select **** 【for update】;
2 应用程序
synchronized
******hibernate对多线程并发的控制:
1 数据库
隔离级别
TRANSACTION_NONE 0
TRANSACTION_UNCOMMITED_READ 1
TRANSACTION_COMMIED_READ 2
TRANSACTION_REPEATABLE_READ 4
TRANSANTION_SERIALIZABLE 8
hibernate.cfg.xml
<property name="connection.isolation">2</property>
select **** 【for update】;
2 应用程序
悲观锁:
认为一定会有两个线程同时访问一个数据
必须针对操作进行加锁:
Query q = session.createQuery("from Student s")
q.setLockMode("s",LokeMode.WRITE);
LockMode:
NONE 不加锁
READ 读锁
WRITE 写锁
UPDATE 表级锁 <===> select **** for update;
乐观锁:
认为一个线程访问的时候,不一定会并发
线程1 线程2
------------------------------------------------------
balance=1000
1000 1000
1000-600 commit
400 1000-200 commit
800
解决:采用一个标志位控制数据的有效性
balance identity 线程1 线程2
-----------------------------------------------------------------
1000 1
1000 1 1000 1
1000-600 1+1 commit
400 if(2>1)提交
1000-200 1+1 commit
if(2>2)不许提交
标志位:
时间戳:
**版本号:
hibernate缓存机制:
一级缓存:Session对象
session.get(Class,Serializble)
session.load(Class,Serializble)
get/load共性:
get和load发送的sql语句结构相同
session--->SessionFactory--->DB
get/load区别:
get:
1 只要调用get方法,则直接发送sql查询
2 get直接查找信息,找不到则返回null
load:
1 调用了load方法,默认不发送sql语句
直到真正使用该对象时,才发送sql查询
load方法返回的对象:没用到信息,则返回代理对象
使用到信息,则返回真正的对象 2 load方法查找不到信息,则报异常 org.hibernate.ObjectNotFoundException
二级缓存:SessionFactory
1 在hibernate.cfg.xml中添加属性
--设置二级缓存类
<property name="cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>二级
--设置query操作使用缓存,否则是对get/load生效
<property name="cache.use_query_cache">true</property>
2 在hbm映射文件中设置使用二级缓存
<class name="Concur" table="concur_time">
<cache usage="read-only|read-write"/>
...
</class>
3 如果使用query语句查询,并且想使用二级缓存
Query.setCacheable(true);
Query.list....
hibernate对象状态及session的各个方法:
transient 临时对象
detached 游离对象
persist 持久化对象
Configuration cfg = new Configuration().configure();
SessionFactory sf = cfg.buildSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction(); 内存 session DB
Concur c = new Concur("hehe");
session.save(c);
tx.commit();
session.close();
hibernate中的N+1问题
在hibernate中,当进行一个表的查询时,当这个表与另外的表是多对一,
或者是一对多关联时,就会出现N+1问题,当查询一条语句时,比如主键name=1,
而与这个name相关联的另一张表对应name的有N个记录,这时就出另外发出N条语句去查询,而我又不要那些记录,这时就是N+1问题。
解决方法:
1.设置lazy=true;
2.在本类DTO中有关联另外表的表对象的声明,在他的get方法上面加上一个@fetch=fetchtype.lazy;
3.在关联的类上面设置@batchsize=2;这时就只发出两条语句。
4.用SQL来查询,写SQL语句时就写成联合查询的形式。