mybatis / mybatis-3 Goto Github PK
View Code? Open in Web Editor NEWMyBatis SQL mapper framework for Java
Home Page: http://mybatis.github.io/mybatis-3/
License: Apache License 2.0
MyBatis SQL mapper framework for Java
Home Page: http://mybatis.github.io/mybatis-3/
License: Apache License 2.0
When 'raw' language is specified, the statement should be parsed only once to provide better performance. Although the main target of this change is batch operations, non-batch operations may get slight performance improvement as well.
Propose to change set node to allow it trim comma prefix
public class SetSqlNode extends TrimSqlNode {
public SetSqlNode(Configuration configuration,SqlNode contents) {
super(configuration, contents, "SET", ",", null, ",");
}
}
Reason:
It is natural for users migrated from ibatis to write code like this
UPDATE user
<set>
<if test="name != null">
name=#{name}
</if>
<if test="desc != null">
,desc=#{desc}
</if>
</set>
Instead of
UPDATE user
<set>
<if test="name != null">
name=#{name},
</if>
<if test="desc != null">
desc=#{desc}
</if>
</set>
The added feature will not break anything, although may use some cpu cycles and slow down a bit.
Right now @resultMap looks like
public @interface ResultMap {
String value();
}
So it looks like only one resultmap can be specified, but in fact it accepts setting the value like this way:
@resultMap("rm1,rm2")
I suggest changing the signature to:
public @interface ResultMap {
String[] value();
}
So it is evident that it supports more than one resultMap and will be used like:
@resultMap("rm1") for one
@resultMap({"rm1","rm2"}) for more than one
We should keep compat with the old method.
Parsing lots of SQL statements from mapper XML file is a time consuming job (up to 10+ seconds for my case). It is annoying to keep user waiting each time at startup of a desktop application.
If MappedStatement which contains parsed SQL statement can be saved and restored in binary data without parsing again, it is very helpful and welcome.
version 3.2.2
we use a 'bind' Element to define match pattern, such as:
<bind name="name_pattern" value="'%' + _parameter.getName() + '%'" />
name is a field of the parameter, if name is null, method @org.apache.ibatis.ognl.OgnlOps.add() will throw a NullPointerException.
We need to extend MapperFactoryBean in order to do additional checks (override) method checkDaoConfig().
Unluckily the MapperScannerConfigurer does not provide an option to specify the bean-class to use:
definition.setBeanClass(MapperFactoryBean.class);
I could not find it anywhere if mybatis already supports such scenario or is it possible with plugins... The case is: I want to generate two cvlasses for every model/table, for example for table 'table' I want to have:
abstract class BaseTable {
//all mybatis generated stuff goes here
}
class Table extends BaseTable {
//empty
}
no - the point is that subsequent generations can overwrite BaseTable class, but final Table class where developers can put some logic must be left intact,
mappers should by default return always 'Table' class instances and operate on that level.
is it possible with current mybatis, with some plugins, or with custom code modyfications? Or maybe it could be built-in in mybatis next release? :)
Hi Team,
I have an issue and I don't know how to resolve it. I read all docs and
didn't find any clue, but doing a fix at the code. (I guess)
I need to map the resultmap from a SP with another one, using Oracle
Procedures (This mean I receive the CURSOR in an OUT parameter).
So, I have no idea how to map it in the association, since the select which
do the call to the nested SP receives a Map), because that was the only way
I found to call a Oracle SP.
This is my code:
{call EEE.GET_EEE_DETAIL ( rs,jdbcType=CURSOR,mode=OUT,resultMap=EEEResultmap,javaType=java.sql.ResultSet}, {id, jdbcType=NUMERIC} )}
Please any advice!
Thank you in advance!
I used mybatis(Version:3.2.2) in my project,and add some sql mapper file into a package,then export to a jar file,when I use it in another project,sometimes it will occur an error,the detail as follow:
https://gist.github.com/Surechun/5727748
Code:https://gist.github.com/Surechun/5727917
Mybatis-config:https://gist.github.com/Surechun/5727895
How do I do,or have any good suggestions?
Many thanks,
Surechun
Here is my batch insert demo code.
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
<constructor-arg index="1" value="BATCH" />
</bean>
-- I use mysql
create table t_user (
id int unsigned auto_increment not null,
name varchar(50) not null,
constraint pk_user primary key (id)
)
autoincrement 101;
public class User {
private Long id;
private String name;
// getters & setters
....
}
public interface UserMapper {
@Select("select * from t_user where id = #{id}")
User find(Long id);
@Insert("insert into t_user(name) values(#{name})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insert(User user);
}
@Test
public void testBatchInsert() {
User user1 = new User();
user1.setName("user 1");
User user2 = new User();
user2.setName("user 2");
userMapper.insert(user1);
userMapper.insert(user2);
// Here will print:
// user1 id: null
// user2 id: null
System.out.println("user1 id: " + user1.getId());
System.out.println("user2 id: " + user2.getId());
// Make a query, this can make mybatis flush batch statements,
// so that we can get the generated keys.
// It looks so strange, but it works.
userMapper.find(null);
// Here will print (xxx is the generated id):
// user1 id: xxx
// user2 id: xxx
System.out.println("user1 id: " + user1.getId());
System.out.println("user2 id: " + user2.getId());
}
I don't know why mybatis doesn't support insert with list/array parameters like ibatis does.
If this feature is supported, mybatis can flush batch statements at the end of the insert operation.
Then we can get the generated keys without strange code.
Allowing an empty namespace can lead to many problems especially with StrictMap.
There is no logical reason to use an empty namespace inside a mapper. The only use I can think of is for very small project with only one mapper file. Even in this case, a namespace is still required to use an interface for the mapper.
The last comments on this issue shows a potential additional problem: https://code.google.com/p/mybatis/issues/detail?id=125
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.531 sec <<< FAILURE!
org.mybatis.scripting.velocity.use.VelocityLanguageTest Time elapsed: 0.53 sec <<< ERROR!
org.apache.ibatis.exceptions.PersistenceException:
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:51)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:35)
at org.mybatis.scripting.velocity.use.VelocityLanguageTest.setUp(VelocityLanguageTest.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:236)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:134)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:113)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:103)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:74)
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating instance. Cause: java.lang.IllegalStateException: Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:106)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:89)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:49)
... 23 more
Caused by: org.apache.ibatis.builder.BuilderException: Error creating instance. Cause: java.lang.IllegalStateException: Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.
at org.apache.ibatis.builder.BaseBuilder.createInstance(BaseBuilder.java:91)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.settingsElement(XMLConfigBuilder.java:198)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:100)
... 25 more
Caused by: java.lang.IllegalStateException: Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.
at org.apache.ibatis.executor.loader.CglibProxyFactory.(CglibProxyFactory.java:50)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at java.lang.Class.newInstance0(Class.java:372)
at java.lang.Class.newInstance(Class.java:325)
at org.apache.ibatis.builder.BaseBuilder.createInstance(BaseBuilder.java:89)
... 27 more
Caused by: java.lang.ClassNotFoundException: Cannot find class: net.sf.cglib.proxy.Enhancer
at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:188)
at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:87)
at org.apache.ibatis.io.Resources.classForName(Resources.java:254)
at org.apache.ibatis.executor.loader.CglibProxyFactory.(CglibProxyFactory.java:48)
See http://code.google.com/p/mybatis/issues/detail?id=781
Reported by m.geri1974, Feb 20, 2013
Hi i am using the mybatis version mybatis-3.1.1,
I have a problem with one-to-one association element.
To reproduce the problem, create a mapper like the following:
<resultMap id="sampleHashResult" type="hashmap">
<result property="f1" column="f1" />
<result property="f2" column="f2" />
<association property="a1" javaType="java.lang.String"
column="{param1=f1}" select="associationTest" />
<association property="a2" javaType="java.lang.String"
column="{param1=f1}" select="associationTest" />
</resultMap>
<select id="sample" resultMap="sampleHashResult">
SELECT 'field1' as f1, 10000 as f2
</select>
<select id="associationTest" resultType="java.lang.String">
select 'test'
</select>
Running the code below:
List results = session.selectList("sample");
for (HashMap r : results) {
System.out.println("a1 class: " + r.get("a1").getClass());
System.out.println("a2 class: " + r.get("a2").getClass());
}
I expected to see the following output:
a1 class: class java.lang.String
a2 class: class java.lang.String
While it prints:
a1 class: class java.lang.String
a2 class: class java.util.ArrayList
It seems that after the first use of the 'association', which returns the expected String result type, then it returns an ArrayList of one element containing the String value (and it's an unexpected behaviour for my application).
I attached the full working eclipse project sample. Let me know if you need any further details.
Thanks.
Edit: I've done a little more testing. It looks like any period in the column name messes it up; spaces have nothing to do with it.
I'm using version 3.2.1. I don't think the ResultHandler is necessary, but it's the scenario I had in my environment where I noticed the bug.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="IncorrectColumnNameTest">
<select id="test" resultType="HashMap">
select 1 as [Space No Period], 2 as [Space. With Period]
</select>
</mapper>
public interface IncorrectColumnNameTest
{
public void test(ResultHandler resultHandler);
}
public Class IncorrectColumnNameTestDao
{
public boolean test(FileWriter fileOutput) throws SQLException
{
final SqlSession session = MyBatisSession.openSession(con);
try
{
final ConsoleResultHandler fileHandler = new ConsoleResultHandler();
final DetailsViewExportMapper mapper = session.getMapper(DetailsViewExportMapper.class);
mapper.test(fileHandler);
} finally {
session.close();
}
public static class ConsoleResultHandler implements ResultHandler
{
public void handleResult(ResultContext rc)
{
final Map<String,Object> row = (Map<String,Object>)rc.getResultObject();
System.out.println( StringUtils.join(row.keySet(), ",") );
System.out.println( StringUtils.join(row.values(), ",") );
}
private String join(Collection<? extends Object> data)
{
String join = "";
for (Object o : data)
{
join += o.toString() + ", "
}
return join;
}
}
}
}
905 [main] DEBUG IncorrectColumnNameTest.test - ooo Using Connection [com.mpti.reportlogiq.server.db.TraceConnection@16ef71]
905 [main] DEBUG IncorrectColumnNameTest.test - ==> Preparing: select 1 as [Space No Period], 2 as [Space. With Period]
906 [main] DEBUG IncorrectColumnNameTest.test - ==> Parameters:
937 [main] TRACE IncorrectColumnNameTest.test - <== Columns: Space No Period, Space. With Period
937 [main] TRACE com.mpti.reportlogiq.server.db.mappers.IncorrectColumnNameTest.test - <== Row: 1, 2
Space No Period, Space. With Period,
1, 2,
Space No Period, Space,
1, { With Period=2},
Hi,
I see there is problem with receiveing null value in stored procedure from parameter output: "c_data OUT sys_refcursor". When sys_refcursor is not opened we will get an error:
at apache.ibatis.executor.resultset.FastResultSetHandler.handleRefCursorOutputParameter(FastResultSetHandler.java:122)
I think that similar problem was here : https://issues.apache.org/jira/browse/IBATIS-220?page=comments#action_12357908
Reported by mgbckr, Today (6 hours ago)
What version of the MyBatis are you using?
MyBatis 3.2.0, MyBatis-Spring 1.2.0
Please describe the problem. Unit tests are best!
When I use the "less than" sign "<" in a Select annotations, I get an exception is thrown when initializing the application context. If I use "<" it works. In previous MyBatis versions using "<" was working. I think it is counter-intuitive to be forced to use XML entities in Java code if not explicitly documented.
What is the expected output? What do you see instead?
No exception :)
Can you provide stack trace, logs, error messages that are displayed?
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mapper' defined in file [/media/data/Projects/EveryAware/workspaces/development/mybatis-invalid-annotation2/target/classes/de/fstyle/test/mybatis/invalid/annotation/mapper/Mapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Could not find value method on SQL annotation. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 38; The content of elements must consist of well-formed character data or markup.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1486)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:608)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83)
at de.fstyle.test.mybatis.invalid.annotation.InvalidAnnotationTest.test(InvalidAnnotationTest.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Could not find value method on SQL annotation. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 38; The content of elements must consist of well-formed character data or markup.
at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:98)
at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1483)
... 35 more
Caused by: org.apache.ibatis.builder.BuilderException: Could not find value method on SQL annotation. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 38; The content of elements must consist of well-formed character data or markup.
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.getSqlSourceFromAnnotations(MapperAnnotationBuilder.java:399)
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parseStatement(MapperAnnotationBuilder.java:241)
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parse(MapperAnnotationBuilder.java:120)
at org.apache.ibatis.binding.MapperRegistry.addMapper(MapperRegistry.java:62)
at org.apache.ibatis.session.Configuration.addMapper(Configuration.java:628)
at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:95)
... 38 more
Caused by: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 38; The content of elements must consist of well-formed character data or markup.
at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:253)
at org.apache.ibatis.parsing.XPathParser.(XPathParser.java:112)
at org.apache.ibatis.scripting.xmltags.XMLScriptBuilder.(XMLScriptBuilder.java:44)
at org.apache.ibatis.scripting.xmltags.XMLLanguageDriver.createSqlSource(XMLLanguageDriver.java:39)
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.buildSqlSourceFromStrings(MapperAnnotationBuilder.java:409)
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.getSqlSourceFromAnnotations(MapperAnnotationBuilder.java:392)
... 43 more
Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 38; The content of elements must consist of well-formed character data or markup.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:391)
at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1404)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.startOfMarkup(XMLDocumentFragmentScannerImpl.java:2583)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2680)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:625)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:488)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:819)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:748)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:239)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:288)
at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:251)
... 48 more
Please provide any additional information below.
See: https://code.google.com/p/fstyle-test/source/browse/#git%2Fbug%2Fmybatis-invalid-annotation
UnPooledDatasource should not call setAutocommit() over a connection if no autocommit setting was provided.
Following situation:
In package 'com.example.beans'
there are two classes:
package com.example.beans;
class A {
public static enum State {
ON,
OFF
}
}
package com.example.beans;
class B {
public static enum State {
FRESH,
ROTTEN
}
}
In the mybatis configuration xml file:
<typeAliases>
<package name="com.example.beans" />
</typeAliases>
This leads to following exception:
[..]
org.apache.ibatis.type.TypeException: The alias 'State' is already mapped to the value 'com.example.beans.A$State'.
at org.apache.ibatis.type.TypeAliasRegistry.registerAlias(TypeAliasRegistry.java:146)
[..]
A solution for me (no idea what sideeffects this may cause) is to replace line 127 in TypeAliasRegistry.java
if (!type.isAnonymousClass() && !type.isInterface()) {
with
if (!type.isAnonymousClass() && !type.isInterface() && !type.isEnum()) {
MyBatis intentionally omits mapping when a mapped column is not found in a result set.
The idea behind this is that resultmaps are reusable so you can intentionally omit some columns in an statement.
Unit tests should cover the wrong mappigs, that is, those mappings with a wrong column (CUSTEMER instead of CUSTOMER). But... of course, it would be desirable to set up mybatis so it fails in case a column is not found.
For that purpose I think we can introduce a new property "strictColumnMapping" so that an exception is thrown if a mapped column is not present in the result set.
I have an scenario where we have a Multimap. That Multimap is an interface that extends from java.util.Collection. What it does is that every element that you put in there gets added to an internal, so every call to add method a key is extracted from the element and a put is called in beneath. We have an implementation which is presented to Mybatis in an association:
<resultMap id="result" type="ObjectId" autoMapping="false"> <collection property="associationCollection" javaType="CollectionMultiMapImpl" ofType="CollectionType" column="ObjectId" select="AssociationCollection.getByObjectId"/> </resultMap>
It was working fine a couple of times but in one case the association was getting loaded by the org.apache.ibatis.executor.BaseExecutor.DeferredLoad.DeferredLoad.load() and looked that the javaType that was specified in the mapping were not provied to the DeferredLoad, trying to create a new instance of the interface Multimap and of course failing.
I'm using Mybatis 3.1.1 with a DerbyDB under java 6.
MyBatis 3.2 does not startup without log4j in the classpath.
Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Priority
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:266)
at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:176)
at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:87)
at org.apache.ibatis.io.Resources.classForName(Resources.java:254)
at org.apache.ibatis.type.TypeAliasRegistry.registerAlias(TypeAliasRegistry.java:153)
at org.apache.ibatis.session.Configuration.(Configuration.java:173)
Greetings!
When I have a table with the following attributes:
Table Name: location
Columns:
I'm running SQL Server and using the MyBatis Generator plugin for Eclipse along with the following plugins:
When I go to generate off of my table described above it successfully generates all of the objects but in this case my Location object is incomplete.
What's happening is that the long column has both the getter (getLong()
) and setter (setLong()
) created but there is no method body that is generated.
Here's the code for Location.java that is generated
import java.io.Serializable;
public class Location implements Serializable {
/**
* This field was generated by MyBatis Generator. This field corresponds to the database column location.location_id
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
private Integer locationId;
/**
* This field was generated by MyBatis Generator. This field corresponds to the database column location.location_name
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
private String locationName;
/**
* This field was generated by MyBatis Generator. This field corresponds to the database column location.latt
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
private Double latt;
/**
* This field was generated by MyBatis Generator. This field corresponds to the database column location.Integer
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
private Integer integer;
/**
* This field was generated by MyBatis Generator. This field corresponds to the database column location.String
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
private String string;
/**
* This field was generated by MyBatis Generator. This field corresponds to the database table location
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
private static final long serialVersionUID = 1L;
/**
* This method was generated by MyBatis Generator. This method returns the value of the database column location.location_id
* @return the value of location.location_id
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public Integer getLocationId() {
return locationId;
}
/**
* This method was generated by MyBatis Generator. This method sets the value of the database column location.location_id
* @param locationId the value for location.location_id
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public void setLocationId(Integer locationId) {
this.locationId = locationId;
}
/**
* This method was generated by MyBatis Generator. This method returns the value of the database column location.location_name
* @return the value of location.location_name
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public String getLocationName() {
return locationName;
}
/**
* This method was generated by MyBatis Generator. This method sets the value of the database column location.location_name
* @param locationName the value for location.location_name
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public void setLocationName(String locationName) {
this.locationName = locationName == null ? null : locationName.trim();
}
/**
* This method was generated by MyBatis Generator. This method returns the value of the database column location.latt
* @return the value of location.latt
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public Double getLatt() {
return latt;
}
/**
* This method was generated by MyBatis Generator. This method sets the value of the database column location.latt
* @param latt the value for location.latt
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public void setLatt(Double latt) {
this.latt = latt;
}
/**
* This method was generated by MyBatis Generator. This method returns the value of the database column location.long
* @return the value of location.long
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public Double getLong() {
}
/**
* This method was generated by MyBatis Generator. This method sets the value of the database column location.long
* @param long the value for location.long
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public void setLong() {
}
/**
* This method was generated by MyBatis Generator. This method returns the value of the database column location.int
* @return the value of location.int
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public Integer getInt() {
}
/**
* This method was generated by MyBatis Generator. This method sets the value of the database column location.int
* @param int the value for location.int
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public void setInt() {
}
/**
* This method was generated by MyBatis Generator. This method returns the value of the database column location.Integer
* @return the value of location.Integer
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public Integer getInteger() {
return integer;
}
/**
* This method was generated by MyBatis Generator. This method sets the value of the database column location.Integer
* @param integer the value for location.Integer
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public void setInteger(Integer integer) {
this.integer = integer;
}
/**
* This method was generated by MyBatis Generator. This method returns the value of the database column location.String
* @return the value of location.String
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public String getString() {
return string;
}
/**
* This method was generated by MyBatis Generator. This method sets the value of the database column location.String
* @param string the value for location.String
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public void setString(String string) {
this.string = string == null ? null : string.trim();
}
/**
* This method was generated by MyBatis Generator. This method returns the value of the database column location.double
* @return the value of location.double
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public Double getDouble() {
}
/**
* This method was generated by MyBatis Generator. This method sets the value of the database column location.double
* @param double the value for location.double
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
public void setDouble() {
}
/**
* This method was generated by MyBatis Generator. This method corresponds to the database table location
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
Location other = (Location) that;
return (this.getLocationId() == null ? other.getLocationId() == null : this.getLocationId().equals(other.getLocationId()))
&& (this.getLocationName() == null ? other.getLocationName() == null : this.getLocationName().equals(other.getLocationName()))
&& (this.getLatt() == null ? other.getLatt() == null : this.getLatt().equals(other.getLatt()))
&& (this.getLong() == null ? other.getLong() == null : this.getLong().equals(other.getLong()))
&& (this.getInt() == null ? other.getInt() == null : this.getInt().equals(other.getInt()))
&& (this.getInteger() == null ? other.getInteger() == null : this.getInteger().equals(other.getInteger()))
&& (this.getString() == null ? other.getString() == null : this.getString().equals(other.getString()))
&& (this.getDouble() == null ? other.getDouble() == null : this.getDouble().equals(other.getDouble()));
}
/**
* This method was generated by MyBatis Generator. This method corresponds to the database table location
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getLocationId() == null) ? 0 : getLocationId().hashCode());
result = prime * result + ((getLocationName() == null) ? 0 : getLocationName().hashCode());
result = prime * result + ((getLatt() == null) ? 0 : getLatt().hashCode());
result = prime * result + ((getLong() == null) ? 0 : getLong().hashCode());
result = prime * result + ((getInt() == null) ? 0 : getInt().hashCode());
result = prime * result + ((getInteger() == null) ? 0 : getInteger().hashCode());
result = prime * result + ((getString() == null) ? 0 : getString().hashCode());
result = prime * result + ((getDouble() == null) ? 0 : getDouble().hashCode());
return result;
}
/**
* This method was generated by MyBatis Generator. This method corresponds to the database table location
* @mbggenerated Thu May 30 14:28:41 EDT 2013
*/
@Override
public String toString() {
}
}
As can be seen above the getters and setters for columns with the name long, int, and double are not properly generated.
You should implement lazy load collections so that usages of the collection outside of a getter/setter don't require that equals or hashcode be called to lazy load.
Hibernate does this using a custom collection if the field is one of the collection interfaces.
MyBatis (3.2.2) keeps a List to hold ResultFlag in ResultMapping, which can add flags and test later whether containing a flag or not. Instead of List, Set is better for the job which will contribute a little for performance improvement.
And my proposal is a specified BitSet holding ResultFlag as below to replace List.
package org.apache.ibatis.mapping;
import java.util.BitSet;
public class ResultFlagSet extends BitSet {
public ResultFlagSet() {
super(ResultFlag.values().length);
}
public ResultFlagSet(ResultFlagSet base) {
this();
this.or(base);
}
public void add(ResultFlag flag) {
set(flag.ordinal(), true);
}
public void clear(ResultFlag flag) {
set(flag.ordinal(), false);
}
public boolean contains(ResultFlag flag) {
return get(flag.ordinal());
}
}
Below is a typical stack trace caused by a syntax error in a mapper xml file. It is not particularly helpful for finding the error. In this particular case, the opening double-quote of a select id was missing. In a typical project, there will be multiple mapper xml files, so the error message should identify the culprit.
org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 690; columnNumber: 14; Open quote is expected for attribute "{1}" associated with an element type "id".
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:106) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:89) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:77) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:67) ~[mybatis-3.2.2.jar:3.2.2]
Caused by: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 690; columnNumber: 14; Open quote is expected for attribute "{1}" associated with an element type "id".
at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:253) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.parsing.XPathParser.<init>(XPathParser.java:122) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.builder.xml.XMLMapperBuilder.<init>(XMLMapperBuilder.java:74) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.builder.xml.XMLMapperBuilder.<init>(XMLMapperBuilder.java:69) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.loadXmlResource(MapperAnnotationBuilder.java:158) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parse(MapperAnnotationBuilder.java:113) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.binding.MapperRegistry.addMapper(MapperRegistry.java:66) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.binding.MapperRegistry.addMappers(MapperRegistry.java:91) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.binding.MapperRegistry.addMappers(MapperRegistry.java:99) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.session.Configuration.addMappers(Configuration.java:631) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:308) ~[mybatis-3.2.2.jar:3.2.2]
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:104) ~[mybatis-3.2.2.jar:3.2.2]
... 30 common frames omitted
Caused by: org.xml.sax.SAXParseException: Open quote is expected for attribute "{1}" associated with an element type "id".
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.impl.XMLScanner.scanAttributeValue(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanAttribute(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source) ~[na:1.7.0_17]
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source) ~[na:1.7.0_17]
at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:251) ~[mybatis-3.2.2.jar:3.2.2]
... 41 common frames omitted
Log4j 2 API has changed so in order to support it we need a new wrapper.
Log4j is in beta4 but probably the API will not change.
This issue is a continuation of http://code.google.com/p/mybatis/issues/detail?id=583. That issue addressed scripting engines in SQL statement construction, and left expression evaluation for a later time. This issue addresses expression evaluation. This issue was also recently discussed on the MyBatis User mailing list in a thread with subject "Expression evaluation".
To be clear, we are talking about #{} and ${} expressions. The former are parameters, while the latter can be used anywhere.
Hello,
I have in my database a column named lt and its counterpart in java is named also like that. However, when I try to test this column ( exemple : <if test="lt != null" > ), I have this stack :
org.apache.ibatis.exceptions.PersistenceException:
Was expecting one of:
":" ...
"not" ...
"+" ...
"-" ...
"~" ...
"!" ...
"(" ...
"true" ...
"false" ...
"null" ...
"#this" ...
"#root" ...
"#" ...
"[" ...
"{" ...
"@" ...
"new" ...
...
<DYNAMIC_SUBSCRIPT> ...
"'" ...
"`" ...
""" ...
<INT_LITERAL> ...
<FLT_LITERAL> ...
]
Can you add a way to escape the operator name or maybe tell me that hopefully if it already exists and that I don't know to search.
Thanks in advance.
When the PooledDataSource pops a new connection it checks if the new connection is bad and if so, it tries to acquire another connection until it failed (maximumIdleConnection + 3) times. Only then it throws an SQLException stating that no connection can be established.
However if a real connection is not created at all because of an SQLException during the attempt to create the Connection, the PooledDataSource will not retry acquiring a good Connectiona again because the SQLException is not caught by the PooledDataSource.
I would expect that both cases are treated the same. Thus marking the connection acquisition attempt as bad and retrying it until the connection establishment failed (maximumIdleConnection + 3) times. Only then should an exception be thrown.
Mybatis version: 3.2.2
If use 'foreach' in mapper.xml, one item will be put into context by applyItem(DynamicContext context, Object o, int i) method and maybe result in wrong boundSql if there is a parameter of statement with the same name as the item name.
Here is an example:
private Connection doGetConnection(String username, String password) throws SQLException {
Properties props = new Properties(driverProperties);
props not a copy of driverProperties
For example, I have one common mapper 'CommonUserMapper':
Now I want to add some custom methods without changing CommonUserMapper.
So I write a new mapper called CustomUserMapper extends from CommonUserMapper:
For this working, I can copy all the codes from the CommonUserMapper.xml to CustomUserMapper.xml.
Of course I can reference some sqls by namespace + ids, but I can't reference the whole select, insert, update, delete...right? So I have to write many duplicate codes.
If the mapper xml can be extended, I think to do this work is more easy.
e.g.
<mapper namespace="demo.CustomUserMapper" extends="demo.CommonUserMapper">
<!-- Now I don't have to copy other statements used by
the methods extended from CommonUserMapper.java -->
<!-- I just define the custom statements -->
<select id="findByXxx" parameterType="string" resultType="User">
<!-- findColumn is defined in CommonUserMapper.xml -->
<include refid="findColumn" />
where xxx = #{value}
</select>
...
</mapper>
Seems that the .zip bundle deployed to maven is too big compared to the .tar.gz
http://repo1.maven.org/maven2/org/mybatis/mybatis/3.2.1/
Having a look inside it you will see that the .tar.gz has been included in the file.
I have multiple for each loops in a single insert as shown in Mapper.xml below. In 3.1.1 and before, the resulting sql would look like
insert into users (id, name, first_attr_1, first_attr_2, second_attr_1, second_attr_2) ...
In 3.2.0, an exception is thrown because the resulting sql is:
insert into users(id, name, first_attr_1, first_attr_2, second_attr_3, second_attr_4) ...
It seems that the index is not being reset before each foreach. A patch with a test for this issue is at https://gist.github.com/jgorinsky/5126131
<insert id="insertUser" parameterType="org.apache.ibatis.submitted.multipleiterates.User">
insert into users
(id,
name,
<foreach item="attr" index="index" collection="firstAttr" separator=",">
first_attr_${index + 1}
</foreach>,
<foreach item="attr" index="index" collection="secondAttr" separator=",">
second_attr_${index + 1}
</foreach>
)
values(
1,
'User1',
<foreach item="attr" index="index" collection="firstAttr" separator=",">
#{attr}
</foreach>,
<foreach item="attr" index="index" collection="secondAttr" separator=",">
#{attr}
</foreach>
)
</insert>
Raw language does not support includes and it should
I ran into a bug in which I expected a result set of about 3600 rows and get 1. The row I get back is the last row of the result set I see in Oracle SQL Developer. I've traced the issue to handleRowValues() in NestedResultSetHandler. Based on tracing thru that code in the debugger the row value gets set by the line:
rowValue = getRowValue(rs, discriminatedResultMap, rowKey, rowKey, null, resultColumnCache, partialObject);
but then nothing actually happens with the value. It would appear that the if statement right after should be within the bracket directly above it (existing source below):
while (shouldProcessMoreRows(rs, resultContext, rowBounds)) {
final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rs, resultMap, null);
final CacheKey rowKey = createRowKey(discriminatedResultMap, rs, null, resultColumnCache);
Object partialObject = objectCache.get(rowKey);
if (partialObject == null && rowValue != null) { // issue #542 delay calling ResultHandler until object ends
if (mappedStatement.isResultOrdered()) objectCache.clear(); // issue #577 clear memory if ordered
callResultHandler(resultHandler, resultContext, rowValue);
}
rowValue = getRowValue(rs, discriminatedResultMap, rowKey, rowKey, null, resultColumnCache, partialObject);
}
if (rowValue != null) callResultHandler(resultHandler, resultContext, rowValue);
In the 3.1.1 release the rowValue is bieng put into another collection:
while (shouldProcessMoreRows(rs, resultContext, rowBounds)) {
final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rs, resultMap, null);
final CacheKey rowKey = createRowKey(discriminatedResultMap, rs, null, resultColumnCache);
final boolean knownValue = objectCache.containsKey(rowKey);
Object rowValue = getRowValue(rs, discriminatedResultMap, rowKey, resultColumnCache);
if (!knownValue) {
resultContext.nextResultObject(rowValue);
resultHandler.handleResult(resultContext);
}
}
EDIT: maybe not quite that simple as I didn't look at the source enough before posting. Based on more debugging the callResultHandler inside the if statement (thats inside the while loop) is never getting called. That would explain why i am only seeing the last row of the resultset in the returned collection. its being put in there by the second if.
Hi
i have issue while inserting list through my batis
How to use foreach loop while insertion
Code ๐
Mapper:
INSERT INTO DataTable (TenantID)
VALUES
<foreach item="Service" collection="ListItems" separator=",">
(#{Service.TenantID})
</foreach>
</insert>
method in service class
public void insert()
{
Wrapper obj = new Wrapper();
List<Service> listField = new List<Service>();
obj.ListItems = new List<Service>();
Service objObjectField = new Service();
objObjectField.TenantID = "1";
objObjectField.ObjectID = "13";
objObjectField.Slot0 = "text";
obj.ListItems.Add(objObjectField);
var objReturnValue = Mapper.Instance().Insert("insert", obj);
}
Thanks
Sravanthi
MyBatis provides only EnumOridinalTypeHandler and EnumTypeHandler, but application (especially enterprise application) tends to persist specified value for each enum literal. It is welcome to provide a generic "EnumValueTypeHandler" to ease the problem.
In my implementation including:
Hi
I am in the process of upgrading camel-mybatis from 3.1.1 to 3.2.0 and hit a problem.
Caused by: org.apache.ibatis.exceptions.PersistenceException:
I do not have CGLIB on my classpath, nor do I want to. I did not have it on my classpath with MyBatis 3.1.1.
So I added an option to my settings to explicit disable lazy loading as follows
<settings>
<!-- disable lazy loading for testing as we do not want CGLIB on our classpath -->
<setting name="lazyLoadingEnabled" value="false"/>
<setting name="useGeneratedKeys" value="false"/>
</settings>
But I still get that failure.
Debugging the code I get to this point
org.apache.ibatis.builder.xml.XMLConfigBuilder#settingsElement
line 198 has:
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory", "CGLIB")));
I wonder if there is some way to run MyBatis without any proxy factory being CGLIB or JAVASSITS?
The old issue is still actual.
Here is the log
JBossFuse:admin@root> start 127
Error executing command: Error starting bundles:
Unable to start bundle 127: Unresolved constraint in bundle org.mybatis.mybatis-spring [127]: Unable to resolve 127.0: missing requirement [127.0] osgi.wiring.package; (osgi.wiring.package=org.springframework.batch.item)
JBossFuse:admin@root> headers 127
MyBatis-Spring (127)
--------------------
Specification-Title = MyBatis-Spring
Archiver-Version = Plexus Archiver
Tool = Bnd-1.50.0
Specification-Version = 1.2.0
Specification-Vendor = MyBatis.org
Implementation-Version = 1.2.0
Build-Jdk = 1.6.0_37
Implementation-Build-Date = 2013-02-20 20:58:18+0100
Implementation-Vendor-Id = org.mybatis
Created-By = Apache Maven Bundle Plugin
Implementation-Title = MyBatis-Spring
Manifest-Version = 1.0
Bnd-LastModified = 1361390302535
X-Compile-Target-JDK = 1.5
Include-Resource = META-INF/LICENSE=LICENSE,META-INF/NOTICE=NOTICE,META-INF/spring.handlers=src/main/java/META-INF/spring.handlers,META-INF/spring.schemas=src/main/java/META-INF/spring.schemas,org/mybatis/spring/config/mybatis-spring-1.2.xsd=src/main/java/org/mybatis/spring/config/mybatis-spring-1.2.xsd
Built-By = stripodi
X-Compile-Source-JDK = 1.5
Implementation-Vendor = MyBatis.org
Bundle-Vendor = MyBatis.org
Bundle-Name = MyBatis-Spring
Bundle-DocURL = http://www.mybatis.org/spring/
Bundle-Description = An easy-to-use Spring3 bridge for MyBatis sql mapping framework.
Bundle-SymbolicName = org.mybatis.mybatis-spring
Bundle-Version = 1.2.0
Bundle-License = http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-ManifestVersion = 2
DynamicImport-Package =
*
Import-Package =
javax.sql,
org.apache.commons.logging,
org.apache.ibatis.builder.xml,
org.apache.ibatis.exceptions,
org.apache.ibatis.executor,
org.apache.ibatis.logging,
org.apache.ibatis.mapping,
org.apache.ibatis.plugin,
org.apache.ibatis.reflection,
org.apache.ibatis.reflection.factory,
org.apache.ibatis.reflection.wrapper,
org.apache.ibatis.session,
org.apache.ibatis.transaction,
org.apache.ibatis.type,
org.springframework.batch;resolution:=optional,
org.springframework.batch.item,
org.springframework.batch.item.database,
org.springframework.beans,
org.springframework.beans.factory,
org.springframework.beans.factory.annotation,
org.springframework.beans.factory.config,
org.springframework.beans.factory.support,
org.springframework.beans.factory.xml,
org.springframework.context,
org.springframework.context.annotation,
org.springframework.context.event,
org.springframework.context.support,
org.springframework.core,
org.springframework.core.annotation,
org.springframework.core.io,
org.springframework.core.type,
org.springframework.core.type.classreading,
org.springframework.core.type.filter,
org.springframework.dao,
org.springframework.dao.support,
org.springframework.jdbc.datasource,
org.springframework.jdbc.support,
org.springframework.transaction.support,
org.springframework.util,
org.w3c.dom
Export-Package =
org.mybatis.spring.annotation;version=1.2.0,
org.mybatis.spring.mapper;version=1.2.0,
org.mybatis.spring.batch;version=1.2.0,
org.mybatis.spring.transaction;version=1.2.0,
org.mybatis.spring.config;version=1.2.0,
org.mybatis.spring;version=1.2.0,
org.mybatis.spring.support;version=1.2.0
As you can see
org.springframework.batch;resolution:=optional,
org.springframework.batch.item,
org.springframework.batch.item.database,
only org.springframework.batch has optional resolution.
The pom.xml should be changed like the following
<osgi.import>org.springframework.batch*;resolution:=optional,*</osgi.import>
Pay attention to additional * after the package name.
gcode: Reported by dcendents, Feb 21 (2 days ago)
Hi,
I found a weird problem with mybatis, spring and declaring statements with databaseId that end up in a StackOverflowError (infinite loop).
mybatis version: 3.1.1
mybatis-spring version: 1.1.1
See the attached project with 2 unit tests. One that fails to load the mybatis configuration, and the second one that force the databaseId to null and the mybatis configuration can be loaded.
I've done a bit of debugging to try and understand the problem and here is what I think is the problem:
(Refer to the attached project for files and content)
The good news is that I think this is a very simple fix, XMLStatementBuilder.databaseIdMatchesCurrent line 130 should set validateIncompleteStatements to false: "MappedStatement previous = this.configuration.getMappedStatement(id, false);"
Also what is strange is I could not reproduce the problem without loading mybatis through spring, but I don't see why that would matter.
Hope the fix is as easy as that and it can be fixed for the next version.
My current workaround is to load the mapping in a different order (B, C and then A).
But there might be a time soon where all our mappings will reference sql fragments from other files and we won't be able to use that workaround.
Thanks
I run into an issue where I mapped a result in a resultMap to Joda's DateTime but didn't register a TypeHandler. Rather than failing with a new error message, it looks like the org.apache.ibatis.executor.resultset.FastResultSetHandler class is returning null in the getPropertyMappingValue method (somewhere near line 316).
This code should be more like this:
protected Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
if (propertyMapping.getNestedQueryId() != null) {
return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
} else if (typeHandler != null) {
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
return typeHandler.getResult(rs, column);
}
throw new TypeHandlerException("Unknown type " + propertyMapping.getJavaType() + ". You need to register a TypeHandler for this type for MyBatis to correctly convert the result.");
}
Instead, it looks like this (notice the return null at the end):
protected Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
if (propertyMapping.getNestedQueryId() != null) {
return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
} else if (typeHandler != null) {
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
return typeHandler.getResult(rs, column);
}
return null;
}
from issue http://code.google.com/p/mybatis/issues/detail?id=686
I'd like to open this issue again because:
look at the code from NestedQueryCacheTest.java especially testThatNestedQueryItemsAreRetrievedFromCache
What will happen if we don't select author before or for example somebody executes method with flushcache before?
Cache method putObject doesn't call from nested query executor .
If you have a trailing space in the alias attribute of a typeAlias definition, like this:
<typeAliases>
<typeAlias alias="User " type="com.example.domain.User" />
</typeAliases>
at runtime you get an exception like this:
java.lang.IllegalArgumentException: Result Maps collection already contains value for com.example.persistence.UserMapper.mapper_resultMap[xxx]_association[xxx]
where the map and association referenced in the exception are ones defined in your mapper.
Removing the trailing space fixes the problem, but it took a long time to track down.
Follows the trace. If select key contains no data MyBatis should not fail.
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: org.apache.ibatis.executor.ExecutorException: Error selecting key or setting result to parameter object. Cause: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
### The error may exist in org/apache/ibatis/submitted/selectkey/Table2.xml
### The error may involve org.apache.ibatis.submitted.selectkey.Table2.insertNoValuesInSelectKey!selectKey-Inline
### The error occurred while setting parameters
### SQL: select * from table2 where name = 'xxx'
### Cause: org.apache.ibatis.executor.ExecutorException: Error selecting key or setting result to parameter object. Cause: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:137)
at org.apache.ibatis.submitted.selectkey.SelectKeyTest.testInsertTable3(SelectKeyTest.java:118)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.apache.ibatis.executor.ExecutorException: Error selecting key or setting result to parameter object. Cause: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at org.apache.ibatis.executor.keygen.SelectKeyGenerator.processGeneratedKeys(SelectKeyGenerator.java:69)
at org.apache.ibatis.executor.keygen.SelectKeyGenerator.processAfter(SelectKeyGenerator.java:47)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:45)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:66)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:45)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:100)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:75)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:148)
... 26 more
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:604)
at java.util.ArrayList.get(ArrayList.java:382)
at org.apache.ibatis.executor.keygen.SelectKeyGenerator.processGeneratedKeys(SelectKeyGenerator.java:65)
... 33 more
The (private) inner class SqlSessionInterceptor refers to (SqlSessionTemplate's) sqlSessionFactory, executorType and exceptionTranslator directly. Imho the (already existing) plublic get-methods should be used.
We have a scenario where we have a "RoutingSqlSessionFactory" (similar to spring's RoutingDatasource) - therefore we need to override getSqlSessionFactory() in order to return the correct SqlSessionFactory depending on a thread-local. We had to copy SqlSessionTemplate because (private class) SqlSessionProxy does not use the public get-methods.
Two additions for logging:
When I use mybatis-3.2.1 version, I find an issue when mybatis framework is resolving jdbc type. There is code fragment as below.
Mapper xml file:
update upc status = #{status,jdbcType=VARCHAR } where uidpk = #{uidPk,jdbcType=BIGINT}
When I invoke this statement, an error occurs, java.lang.IllegalArgumentException: No enum const class org.apache.ibatis.type.JdbcType.VARCHAR. Finally, I find this error is thrown from org.apache.ibatis.builder.resolveJdbcType, because parameter's jdbcType has a blank space on the right of VARCHAR. But I couldn't find the same issue in mybatis version 3.1.1.
MyBatis version 3.2.1
SELECT * FROM TABLE WHERE
<foreach collection="filters" index="key" item="value" separator="AND">
UPPER(TRIM(${key})) = UPPER(TRIM(#{value}))
</foreach>
filters is Map<String,String>
In example above ${key} is replaced by ordinal number - 0, 1, 2 etc.
When I change to #{key} it is replaced by true map key but query is not usable since I need column name, not property.
Maybe it's good idea to use value.key/value.value and leave index for ordinal numbering?
Please ignore this issue. I didn't know that an issue is automatically created for a pull request
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.