DB2用mybatis批量update的问题

DB2用mybatis批量update的问题,第1张

MySQL没有提供直接的方法来实现批量,但可以使用case when语法来实现这个功能。

UPDATE course

SET name = CASE id

WHEN 1 THEN 'name1'

WHEN 2 THEN 'name2'

WHEN 3 THEN 'name3'

END,

title = CASE id

WHEN 1 THEN 'New Title 1'

WHEN 2 THEN 'New Title 2'

WHEN 3 THEN 'New Title 3'

END

WHERE id IN (1,2,3)

问题一:用spoon设计了一个转换,主要功能是从数据文件中读取记录,然后直接存入数据库(我们使用的是IBM DB2)。在执行转换的过程中,遇到了如下异常:2006/11/03 16:04:12 - 数据库输出.0 - ERROR (version 2.3.1, build 63 from 2006/09/14 12:04:05 @ sam) : An error occurred intialising this step:2006/11/03 16:04:12 - 数据库输出.0 - ERROR (version 2.3.1, build 63 from 2006/09/14 12:04:05 @ sam) : Error occured while trying to connect to the database2006/11/03 16:04:12 - 数据库输出.0 - ERROR (version 2.3.1, build 63 from 2006/09/14 12:04:05 @ sam) :2006/11/03 16:04:12 - 数据库输出.0 - ERROR (version 2.3.1, build 63 from 2006/09/14 12:04:05 @ sam) : Error connecting to database: (using class com.ibm.db2.jcc.DB2Driver)2006/11/03 16:04:12 - 数据库输出.0 - ERROR (version 2.3.1, build 63 from 2006/09/14 12:04:05 @ sam) : Unicode string can't convert to Ebcdic string2006/11/03 16:04:12 - 数据库输出 - ERROR (version 2.3.1, build 63 from 2006/09/14 12:04:05 @ sam) : 错误初始化步骤[数据库输出]2006/11/03 16:04:12 - be.ibridge.kettle.trans.Trans - ERROR (version 2.3.1, build 63 from 2006/09/14 12:04:05 @ sam) : !Trans.Log.StepFailedToInit!2006/11/03 16:04:12 - be.ibridge.kettle.trans.Trans - ERROR (version 2.3.1, build 63 from 2006/09/14 12:04:05 @ sam) : 无法初始化至少一个步骤. 执行无法开始!在遇到该异常之前,我已经对数据库连接进行了测试,完全可以正常连接。之后我又使用spoon的SQL编辑器连接数据库并插入记录,仍然没有任何异 常。换为连接MySQL然后执行该转换也没有问题,数据可以正常的写入数据库。我们首先考虑到的是spoon使用的字符集和DB2的字符集不匹配。于是更 改数据库的字符集,将其改为utf-8,然后再执行转换,依然抛出上面的异常。后来在查阅资料的时候发现DB2 type 4的jdbc驱动可能存在字符编码转换的问题,于是察看spoon使用的DB2 jdbc驱动的类型,正是type4的驱动!于是考虑配置spoon,使其使用type3的jdbc驱动,让我们郁闷的是spoon里根本没有对驱动类型 进行配置的地方!无奈中,我们找出了kettle的源码,几经周折,最终在be.ibridge.kettle.core.database包中的 DB2DatabaseMeta.Java文件中找到了kettle的DB2连接配置,源程序如下:public String getDriverClass()...{if (getAccessType()==DatabaseMeta.TYPE_ACCESS_ODBC)...{return "sun.jdbc.odbc.JdbcOdbcDriver" }else...{return "com.ibm.db2.jcc.DB2Driver"}}public String getURL()...{if (getAccessType()==DatabaseMeta.TYPE_ACCESS_ODBC)...{return "jdbc:odbc:"+getDatabaseName()}else...{return "jdbc:db2://"+getHostname()+":"+getDatabasePortNumberString()+"/"+getDatabaseName()}}对这两个方法进行修改,改为以下代码: public String getDriverClass()...{if (getAccessType()==DatabaseMeta.TYPE_ACCESS_ODBC)...{return "sun.jdbc.odbc.JdbcOdbcDriver"}else...{return "com.ibm.db2.jdbc.NET.DB2Driver"}}public String getURL()...{if (getAccessType()==DatabaseMeta.TYPE_ACCESS_ODBC)...{return "jdbc:odbc:"+getDatabaseName()}else...{return "jdbc:db2:"+getHostname()+":"+getDatabaseName()}编译修改后的文件,用新的DB2DatabaseMeta.class代替kettle原来的文件,重新打包(注意要把DB2自带的驱动程序包也打进去),重新运行该转换,一切ok啦!问题二:无论使用spoon还是使用chef的时候都会询问你有没有资源库,第一次运行时当然是没有了,那么就新建吧。这时,让人郁闷的东西出现了,在向数据库(这里还是DB2 啦)中建表的时候会出现如下异常,导致资源库创建失败:Couldn't execute SQL: CREATE TABLE R_NOTE(ID_NOTE DECIMAL(9), VALUE_STR CLOBBLOB(2000000) UNKNOWN, GUI_LOCATION_X DECIMAL(6), GUI_LOCATION_Y DECIMAL(6), GUI_LOCATION_WIDTH DECIMAL(6), GUI_LOCATION_HEIGHT DECIMAL(6))DB2 SQL error: SQLCODE: -104, SQLSTATE: 42601, SQLERRMC: CLOBBLOBIMAL(9) , VALUE_STR<clob>java.lang.reflect.InvocationTargetException: Error creating or upgrading repository:Couldn't execute SQL: CREATE TABLE R_NOTE(ID_NOTE DECIMAL(9), VALUE_STR CLOBBLOB(2000000) UNKNOWN, GUI_LOCATION_X DECIMAL(6), GUI_LOCATION_Y DECIMAL(6), GUI_LOCATION_WIDTH DECIMAL(6), GUI_LOCATION_HEIGHT DECIMAL(6))DB2 SQL error: SQLCODE: -104, SQLSTATE: 42601, SQLERRMC: CLOBBLOBIMAL(9) , VALUE_STR<clob>at be.ibridge.kettle.repository.dialog.UpgradeRepositoryProgressDialog$1.run(UpgradeRepositoryProgressDialog.java:66)at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalContext.java:346)at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:291)at org.eclipse.jface.dialogs.ProgressMonitorDialog.run(ProgressMonitorDialog.java:447)at be.ibridge.kettle.repository.dialog.UpgradeRepositoryProgressDialog.open(UpgradeRepositoryProgressDialog.java:74)at be.ibridge.kettle.repository.dialog.RepositoryDialog.create(RepositoryDialog.java:450)at be.ibridge.kettle.repository.dialog.RepositoryDialog.access$800(RepositoryDialog.java:64)at be.ibridge.kettle.repository.dialog.RepositoryDialog$5.handleEvent(RepositoryDialog.java:267)at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:928)at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3348)at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2968)at be.ibridge.kettle.repository.dialog.RepositoryDialog.open(RepositoryDialog.java:291)at be.ibridge.kettle.repository.dialog.RepositoriesDialog$3.widgetSelected(RepositoriesDialog.java:297)。。。more异常信息很长,但请大家注意上面红色标记的异常。CLOBBLOB(2000000) UNKNOWN 觉不觉的这个类型很奇怪?没错,就是它导致建表失败的。通过分析源码,最终还是在DB2DatabaseMeta.java中找到以下方法:public String getFieldDefinition(Value v, String tk, String pk, boolean use_autoinc, boolean add_fieldname, boolean add_cr)String retval=""String fieldname = v.getName()intlength= v.getLength()intprecision = v.getPrecision()if (add_fieldname) retval+=fieldname+" "int type = v.getType()switch(type)...{case Value.VALUE_TYPE_DATE : retval+="TIMESTAMP"breakcase Value.VALUE_TYPE_BOOLEAN: retval+="CHARACTER(1)"breakcase Value.VALUE_TYPE_NUMBER :case Value.VALUE_TYPE_INTEGER:case Value.VALUE_TYPE_BIGNUMBER:if (fieldname.equalsIgnoreCase(tk) &&use_autoinc) // Technical key: auto increment field!...{retval+="BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 0, INCREMENT BY 1, NOCACHE)"}else...{if (length>0)...{retval+="DECIMAL("+lengthif (precision>0)...{retval+=", "+precision}retval+=")"}else...{retval+="FLOAT"}}breakcase Value.VALUE_TYPE_STRING:if (length>getMaxVARCHARLength() || length>=DatabaseMeta.CLOB_LENGTH)...{retval+="CLOB"}else...{retval+="VARCHAR"if (length>0)...{retval+="("+length}else...{retval+="("// Maybe use some default DB String length?}retval+=")"break}case Value.VALUE_TYPE_BINARY:if (length>getMaxVARCHARLength() || length>=DatabaseMeta.CLOB_LENGTH)...{retval+="BLOB("length")"}else...{if (length>0)...{retval+="CHAR("length") FOR BIT DATA"}else...{retval+="BLOB"// not going to work, but very close}break} default:retval+=" UNKNOWN"break}if (add_cr) retval+=Const.CRreturn retval}注意方法中红色标记的部分,在这里竟然出现了严重的逻辑错误:case语句里并不是每个分支都有break;因此当有满足Value.VALUE_TYPE_STRING分支的if语句的条件出现,就会顺序执行后面所有的分支(注意,满足Value.VALUE_TYPE_STRING分支的if语句的条件同样也满足Value.VALUE_TYPE_BINARY 分支的if语句的条件)。这就导致了最终的字符串变成了我们前面看到的那个奇怪的数据库字段类型。那么解决方法就简单了,修改的代码如下:case Value.VALUE_TYPE_STRING:if (length>getMaxVARCHARLength() || length>=DatabaseMeta.CLOB_LENGTH)...{retval+="CLOB"}else...{retval+="VARCHAR"if (length>0)...{retval+="("+length}else...{retval+="("// Maybe use some default DB String length?}retval+=")"} breakcase Value.VALUE_TYPE_BINARY:if (length>getMaxVARCHARLength() || length>=DatabaseMeta.CLOB_LENGTH)...{retval+="BLOB("length")"}else...{if (length>0)...{retval+="CHAR("length") FOR BIT DATA"}else...{retval+="BLOB"// not going to work, but very close}}breakdefault: 。。。。。。这样就好了,不过第二个问题好像kettle现在的版本已经修改好了


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/7663787.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-08
下一篇 2023-04-08

发表评论

登录后才能评论

评论列表(0条)

保存