`
demojava
  • 浏览: 541173 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Hibernate初探(-)

    博客分类:
  • JAVA
阅读更多

  在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语句时就写成联合查询的形式。

  • 大小: 107.4 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics