Hiberante批量处理(Hibernate API 转为 JDBC API 执行)

 今天使用Excel导入到数据库
但是要进行批量插入, 使用的是JDBC的方式进行的,可是就是在事务处理的时候没有成功,
我在网上找了一些资料,这次又是使用Hibernate的回调机制。成功了!

分享一下~

Hibernate中的Dao层的代码:
package teach.dao.adminpart;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class StudentCourseBatchDaoImp extends HibernateDaoSupport implements
StudentCourseBatchDao {
/*
*
* JDBC API 方式处理
*
*
*/

public void addTeacherCourseByBatch(final String excelPath,
final String courseid, final Integer grade, final Integer term)
throws SQLException, FileNotFoundException, IOException {
/*
*
* 批量添加学生成绩的语句
*
* 绕过Hibernate的API来处理
*
* 采用JDBC的API 来处理
*
* 1、修改方法的前缀,使方法绕过Spring的声明式事务( 经过测试,这里Spring的事务没有作用了 )
* 2、通过session获取事务,不过该事务无法成功启动。
*
* 3、不如手启动JDBC的事务。
*/

this.getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {

HSSFWorkbook workBook;
int rowsLength = 0;
HSSFSheet sheet = null;

try {
workBook = new HSSFWorkbook(new FileInputStream(excelPath));
sheet = workBook.getSheet("Sheet1");// 取Excel的第一页就可以了。
rowsLength = sheet.getPhysicalNumberOfRows(); // 获取行数.
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

String studentid;
int mark;

java.sql.Date year = new java.sql.Date(new java.util.Date()
.getTime()); // 使用那个java.sql.Date

Connection conn = session.connection();

String sql = "insert into studentcourse(studentid,courseid,mark,remark,stage,grade,term,year)"
+ " values(?,?,?,?,?,?,?,?)";
PreparedStatement stmt = conn.prepareStatement(sql);

for (int i = 1; i < rowsLength; i++) {
HSSFRow row = sheet.getRow(i);

if (null != row) {

HSSFCell cell_0 = row.getCell((short) 0);
studentid = cell_0.getStringCellValue();

HSSFCell cell_2 = row.getCell((short) 2);
mark = (int) cell_2.getNumericCellValue();

stmt.setString(1, studentid);
stmt.setString(2, courseid);
stmt.setInt(3, mark);
stmt.setInt(4, 0);
stmt.setInt(5, 2);
stmt.setInt(6, grade);
stmt.setInt(7, term);
stmt.setDate(8, year);
stmt.addBatch();
}

stmt.executeBatch();

}
return null;
}
});
}
}



要看到它有点难度啊,因为我加入了Apache项目下的POI 读取Excel文件,这样大家应该清楚一些了吧!!

 

------------------------

Hibernate中HIbernateTemplate回调机制(一)

学习了spring的HibernateTemplate类部分源码,总结一下自己对回调模式的理解。

在dao里经常有这样的语句

代码

public E findById(Serializable id)   
    {   
        return (E) getHibernateTemplate().get(clazz, id);   
    }   
HibernateTemplate类源码



代码
public Object get(Class entityClass, Serializable id) throws DataAccessException {   
        return get(entityClass, id, null);   
    } 


 
代码
public Object get(final Class entityClass, final Serializable id, final LockMode lockMode)   
            throws DataAccessException {   
  
        return execute(new HibernateCallback() {   
            public Object doInHibernate(Session session) throws HibernateException {   
                if (lockMode != null) {    
                    return session.get(entityClass, id, lockMode);   
                }   
                else {   
                    return session.get(entityClass, id);   
                }   
            }   
        }, true);   
    }


  
代码
public Object execute(HibernateCallback action) throws DataAccessException {   
        return execute(action, isExposeNativeSession());   
    } 


 
代码

public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {   
        Assert.notNull(action, "Callback object must not be null");   
  
        Session session = getSession();   
        boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());   
        if (existingTransaction) {   
            logger.debug("Found thread-bound Session for HibernateTemplate");   
        }   
  
        FlushMode previousFlushMode = null;   
        try {   
            previousFlushMode = applyFlushMode(session, existingTransaction);   
            enableFilters(session);   
            Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));   
            Object result = action.doInHibernate(sessionToExpose);          flushIfNecessary(session, existingTransaction);   
            return result;   
        }   
        catch (HibernateException ex) {   
            throw convertHibernateAccessException(ex);   
        }   
        catch (SQLException ex) {   
            throw convertJdbcAccessException(ex);   
        }   
        catch (RuntimeException ex) {   
            // Callback code threw application exception...   
            throw ex;   
        }   
        finally {   
            if (existingTransaction) {   
                logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");   
                disableFilters(session);   
                if (previousFlushMode != null) {   
                    session.setFlushMode(previousFlushMode);   
                }   
            }   
            else {   
                // Never use deferred close for an explicitly new Session.   
                if (isAlwaysUseNewSession()) {   
                    SessionFactoryUtils.closeSession(session);   
                }   
                else {   
                    SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());   
                }   
            }   
        }   
    }   


HibernateTemplate类是对hibernate操作的封装。如果要自己写hibernate的操作,最麻烦的是那些要检查的错误,而且每一个地方都一样。不一样的地方只是真正对数据库操作的语句。spring的想法是一样的代码抽取出来写成一个HibernateTemplate中的execute方法。execute的方法参数是HibernateCallback接口类。HibernateCallback里面定义了一个doInHibernate的方法。因为这个方法是变的。比如你是查找数据方法应该就是:session.load()。删除数据就是session.delete().这样的话查询数据库的方法用execute方法。



HibernateCallback 接口类 (* 关键在于 为什么要实施这个接口 !!)

代码
public interface HibernateCallback {   
  
    Object doInHibernate(Session session) throws HibernateException, SQLException;   
}  
然后使用内部类的形式把HibernateCallback中的方法doInHibernate实例化。



代码

new HibernateCallback() {   
            public Object doInHibernate(Session session) throws HibernateException {   
                if (lockMode != null) {    
                    return session.get(entityClass, id, lockMode);   
                }   
                else {   
                    return session.get(entityClass, id);   
                }   
            }   
总的想法就是不变的东西可以抽象出一个方法。比如对异常的检查。变的东西,比如对数据库的操作,抽象出一个接口的方法。

总结

JAVA的CALLBACK通过接口来实现。

例:

1.HibernateTemplate,内联类

2.内联类实现接口HibernateCallback的doInHibernate 方法

3.HibernateTemplate拥有一个参数为HibernateCallback接口类型的函数execute(HibernateCallback action)方法.

4.调用HibernateTemplate的get方法时,将内联类传给了excute方法

5.执行excute方法时,(你调用它)

已取得内联类,就可以随时回调它所实现的HibernateCallback接口中的方法了,

这时它反过来调用你的方法(它调用你),这就是回调了.


就是调用系统的一个方法,传进去一个接口的实现类 or 匿名类。

然后系统的方法调用接口申明的方法,并且注入相应的参数

Buaawhl:

IoC, Functor, Visitor 都是 callback。

就是一个 Template Methond 里面的flow不变,某一个步骤的具体操作变化,这个变化部需要  从外部(参数,或者属性,或者 override parent method)注入。

类似于从前的 C 回调函数指针。

MainFlow ( callback ){

step1;

....

callback( someThing );

....

stepN;

}



注意配置文件里applictionContext.xml

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>


<bean id="baseTransactionProxy" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
  <property name="transactionManager">
   <ref bean="transactionManager" />
  </property>
  <property name="transactionAttributes">
  <props>
   <prop key="save*">PROPAGATION_REQUIRED</prop>
   <prop key="update*">PROPAGATION_REQUIRED</prop>
   <prop key="find*">PROPAGATION_REQUIRED</prop>
   <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
  </props>
  </property>
</bean>

 

 

 

谈谈回调吧,以前学java的时候居然没接触到这个词汇,汗,最近研究hibernate和spring结合时,发现spring实现hibernate时应用了回调机制,于是google了很多次,终于有所体会了,现在做下小小的总结,以便加深印象!

 java回调机制:

软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。

同步调用是一种阻塞式调用,调用 方要等待对方执行完毕才返回,它是一种单向调用;

回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;

异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。

这是搜索的一点比较枯燥的理论解释了,算是红体部分让我稍微明白了一点是怎么个回事,然后又看到一个例子,又让我明白不少。

看看在JAVA里的例子:

public class Test{

   public static void main(String[] args){

     FooBar foo=new FooBar();

/**注意下面的这项代码片段,它给foo对象传递了一个实现ICallBack接口的匿名类,这样FooBar类的对象就取

得了一个实现接口的类,因此FooBar可以在任何时候调用接口中的方法*/

     foo.setCallBack(new ICallBack(){

     public void postExec(){System.out.println("我(postExec)是在Test类中实现的,但我不能被Test的对象引用,"+

     "而由FooBar对象调用");}

     });

   }

}

public interface ICallBack(){

  void postExec();

}

public class FooBar..{

  private ICallBack callBack;

  public void setCallBack(ICallBack callBack){

    this.callBack=callBack;

  }

/*我没有实现接口,但是我取得了一个实现接口的对象,而这个对象是其他类调用我的方法( setCallBack ())

时所赋给我的,因此我可以在业务需要的地方来调用实现接口的类里面的方法*/

  public void doSth(){

     ....

     callBack.postExec();

  }

  ..

}

上述两个类的描述:

  1.class   A,class   B  

  2.class   A实现接口ICallBack  

  3.class   B拥有一个参数为ICallBack接口类型的函数setCallBack(ICallBack   o)  

  4.class   A运行时调用class   B中setCallBack函数,以自身传入参数  

  5.class   B已取得A,就可以随时回调A所实现的ICallBack接口中的方法

 

下面在来看看在Hibernate中如何构造自己的HibernateTemplate模版

使用模板模式简化DAO操作Hibernate

 


在使用Spring + Hibernate做开发过时,在写DAO的时候使用过Spring的HibernateDaoSupport类,然后在实现的时候就可以很轻松的使用getHibernateTemplate()方法之后就可以调用save()、delete()、update()等Hibernate的Session的操作,很简单。比如:
  
  getHibernateTemplate().save(user);

 但是我们在使用Hibernate的时候不一定会使用Spring,所以我们可以模仿Spring的处理方式,做一个Hibernate的模板,使用模板模式来简化我们的开发,其主要的目的就是为了简化开发,使代码达到最大化的重用,另外呢,是帮助自己对回调机制有一个更深层的了解。

1.我们现来实现一个Hibernate模板:
  
  package kick.hibernate;
  
  import net.sf.hibernate.HibernateException;
  import net.sf.hibernate.Session;
  import net.sf.hibernate.Transaction;
  
  public class HibernateTemplate{
  public static Object run(HibernateCallback callback) throws HibernateException{
  Session session = null;
  Transaction tx = null;
  try {
  session = HibernateSessionutil.currentSession();
  tx = session.beginTransaction();
  Object result = callback.execute(session);
  tx.commit();
  session.flush();
  return result;
  } catch (HibernateException e) {
  tx.rollback();
  return null;
  } finally {
  HibernateSessionutil.closeSession();
  }
  }


这里类很简单,就是使用一个实现HibernateCallBack接口的一个回调类,在调用的时候根据具体的需求实现HibernateCallBack类。

强调一下偶,仔细体会红色部分的代码,其实这部分就是对回调的最好的体现,callbak肯定是一个实现了HibernateCallback 接口的类的对象,而execute(Session s)的具体实现就是在这个实现类中实现的,但是我们没法显示的调用该实现类里面的具体方法,如execute(),而只是通过接口的形式来调用方法,晕,说了一大堆,把我自己都快整糊涂了,算了,还是继续写例子吧,结合例子看,可能明白的更快一些。

2.回掉接口HibernateCallBack:
  package kick.hibernate;
  
  import net.sf.hibernate.HibernateException;
  import net.sf.hibernate.Session;
  
  public interface HibernateCallBack {
  Object execute(Session session)throws HibernateException;
  }

好了,到此为止我们就可以使用这个模板了,可以用如下的方式使用:

//调用的时候根据具体的需求实现HibernateCallBack类。 我在这里是实现保存的业务

HibernateTemplate.run(

new HibernateCallback() {
  public Object execute(Session session) throws HibernateException {
  session.save(user);
  return null;
  }
  }   //这其实是一个匿名类

);

不过这还没有达到想Spring里面那样简单,不要着急,“面包会有的”呵呵,我们会达到的。

3.实现我们自己的HibernateSupport类:
  
  从上面的代码可以看出,我们要自己实现HibernateCallback接口,而每次我们实现的时候又重复代码了。因此我们再抽象,讲这些实现放到我们的HibernateSupport类里面去。看看我们上面的代码就知道我们实现HibernateCallback接口的目的就是为了调用session.save()方法,即session的方法。代码如下:
  
  package kick.hibernate;
  
  import java.io.Serializable;
  
  import net.sf.hibernate.HibernateException;
  import net.sf.hibernate.Session;
  
  public class HibernateSupport{
  
  public Object save(final Object object) throws HibernateException{
  return HibernateTemplate.run(new HibernateCallBack(){
  
  public Object execute(Session session) throws HibernateException {
  session.save(object);
  return null;
  }
  
  });
  }
  public Object save(final Object object,final Serializable id) throws HibernateException{
  return HibernateTemplate.run(new HibernateCallBack(){
  
  public Object execute() throws HibernateException {
  session.save(object,id);
  return null;
  }
  
  });
  }
  
  public Object saveOrUpdate(final Object object) throws HibernateException{
  return HibernateTemplate.run(new HibernateCallBack(){
  
  public Object execute(Session session) throws HibernateException {
  session.saveOrUpdate(object);
  return null;
  }
  
  });
  }
  ……………………………………………………………………………………
  ……………………………………………………………………………………
  ……………………………………………………………………………………
  
  调用一些其他的session的方法。
  
  }
  
  4.抽象RootDao:
  
  该类为抽象类,在实现自己的DAO类的时候继承该类。该类的有一个HibernateSupport的对象,在子类中使用getHibernateTemplate()方法就可以得到该对象,然后调用它对应的方法。实现代码如下:
  
  package kick.hibernate.dao;
  
  import net.sf.hibernate.Session;
  import kick.hibernate.HibernateTemplateImpl;
  
  public abstract class RootDao {
  private HibernateSupport temp = null;
  
  /**
  * @return Returns the temp.
  */
  public HibernateTemplateImpl getHibernateTemplate(Session session) {
  return new HibernateSupport();
  }
  }
  
  5.使用例子:
  
  定义一个自己的DAO类,实现代码如下:
  
  public class UserDaoImpl extends RootDao implements UserDaoInterface{
  public void saveUser(User user) throws KickException {
  getHibernateTemplate().saveOrUpdate(user);
  }
  ……………………………………………………………………………………
  实现其他的方法
  ……………………………………………………………………………………
  }
  看到没有?红色的代码,就实现了Spring的HibernateSupport了吧

好了,回调暂时这这里就告一段落了......

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值