今天使用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回调机制(一)
在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了吧
好了,回调暂时这这里就告一段落了......