<bean id="PropertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="config.properties" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<property name="initialSize" value="50"/>
<property name="maxActive" value="100"/>
<property name="maxIdle" value="50"/>
<property name="maxWait" value="50"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" abstract="false"
lazy-init="false" autowire="default" >
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
driver=com.ibm.db2.jcc.DB2Driver
url=jdbc:db2://100.100.100.76:60008/mpsdb
username=mps
password=mps
package org.q.map;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class TestJdbcTemplateQueryForMap extends TestCase {
public void testLinkedCaseInsensitiveMap() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beanContext.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate)ctx.getBean("jdbcTemplate");
Map<String, Object> map = jdbcTemplate.queryForMap("select * from pstranlist fetch first 1 rows only");
//spring3.1.3以后LinkedCaseInsensitiveMap可以检测关键字(不区分大小写)的唯一性 ,下面这行代码应该会出问题
map.put("pkgcode", "tttt");
Iterator<String> iter = map.keySet().iterator();
while(iter.hasNext()) {
String key = iter.next();
Object value = map.get(key);
System.out.println(key + " : " + value);
}
}
/**
* LinkedHashMap出现相同key时,后者的值将前者的值覆盖,但是前者的顺序不变, 后者不再加入到map中
*/
public void testLinkedHashMap() {
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
map.put("aaa", 1);
map.put("bbb", 1);
map.put("AAA", 1);
map.put("aaa", 2);
Iterator<String> iter = map.keySet().iterator();
while(iter.hasNext()) {
String key = iter.next();
if("bbb".equals(key)) map.put("bbb", 5);
Object value = map.get(key);
System.out.println(key + " : " + value);
}
}
}
从jdbcTemplate.queryForMap追踪代码可以发现最后会进入ColumnMapRowMapper类的
public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
Map<String, Object> mapOfColValues = createColumnMap(columnCount);
for (int i = 1; i <= columnCount; i++) {
String key = getColumnKey(JdbcUtils.lookupColumnName(rsmd, i));
Object obj = getColumnValue(rs, i);
mapOfColValues.put(key, obj);
}
return mapOfColValues;
}
方法, 其中createColumnMap的内容如下:
/**
* Create a Map instance to be used as column map.
* <p>By default, a linked case-insensitive Map will be created.
* @param columnCount the column count, to be used as initial
* capacity for the Map
* @return the new Map instance
* @see org.springframework.util.LinkedCaseInsensitiveMap
*/
@SuppressWarnings("unchecked")
protected Map<String, Object> createColumnMap(int columnCount) {
return new LinkedCaseInsensitiveMap<Object>(columnCount);
}
LinkedCaseInsensitiveMap 源码如下:
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.util;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
/**
* {@link LinkedHashMap} variant that stores String keys in a case-insensitive
* manner, for example for key-based access in a results table.
*
* <p>Preserves the original order as well as the original casing of keys,
* while allowing for contains, get and remove calls with any case of key.
*
* <p>Does <i>not</i> support <code>null</code> keys.
*
* @author Juergen Hoeller
* @since 3.0
*/
public class LinkedCaseInsensitiveMap<V> extends LinkedHashMap<String, V> {
private final Map<String, String> caseInsensitiveKeys;
private final Locale locale;
/**
* Create a new LinkedCaseInsensitiveMap for the default Locale.
* @see java.lang.String#toLowerCase()
*/
public LinkedCaseInsensitiveMap() {
this(null);
}
/**
* Create a new LinkedCaseInsensitiveMap that stores lower-case keys
* according to the given Locale.
* @param locale the Locale to use for lower-case conversion
* @see java.lang.String#toLowerCase(java.util.Locale)
*/
public LinkedCaseInsensitiveMap(Locale locale) {
super();
this.caseInsensitiveKeys = new HashMap<String, String>();
this.locale = (locale != null ? locale : Locale.getDefault());
}
/**
* Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap}
* with the given initial capacity and stores lower-case keys according
* to the default Locale.
* @param initialCapacity the initial capacity
* @see java.lang.String#toLowerCase()
*/
public LinkedCaseInsensitiveMap(int initialCapacity) {
this(initialCapacity, null);
}
/**
* Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap}
* with the given initial capacity and stores lower-case keys according
* to the given Locale.
* @param initialCapacity the initial capacity
* @param locale the Locale to use for lower-case conversion
* @see java.lang.String#toLowerCase(java.util.Locale)
*/
public LinkedCaseInsensitiveMap(int initialCapacity, Locale locale) {
super(initialCapacity);
this.caseInsensitiveKeys = new HashMap<String, String>(initialCapacity);
this.locale = (locale != null ? locale : Locale.getDefault());
}
@Override
public V put(String key, V value) {
this.caseInsensitiveKeys.put(convertKey(key), key);
return super.put(key, value);
}
@Override
public void putAll(Map<? extends String, ? extends V> map) {
if (map.isEmpty()) {
return;
}
for (Map.Entry<? extends String, ? extends V> entry : map.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public boolean containsKey(Object key) {
return (key instanceof String && this.caseInsensitiveKeys.containsKey(convertKey((String) key)));
}
@Override
public V get(Object key) {
if (key instanceof String) {
return super.get(this.caseInsensitiveKeys.get(convertKey((String) key)));
}
else {
return null;
}
}
@Override
public V remove(Object key) {
if (key instanceof String ) {
return super.remove(this.caseInsensitiveKeys.remove(convertKey((String) key)));
}
else {
return null;
}
}
@Override
public void clear() {
this.caseInsensitiveKeys.clear();
super.clear();
}
/**
* Convert the given key to a case-insensitive key.
* <p>The default implementation converts the key
* to lower-case according to this Map's Locale.
* @param key the user-specified key
* @return the key to use for storing
* @see java.lang.String#toLowerCase(java.util.Locale)
*/
protected String convertKey(String key) {
return key.toLowerCase(this.locale);
}
}