spring jdbctemplate 項目使用完整記錄

1、前言

項目使用jdbctemplate已經一段時間了,對於jdbcTemplate的使用有了一些小當心得,這裏總結後跟你們分享下。java

 

 

2、spring xml 配置jdbcTemplate 

 

 

<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName">
			<value>com.mysql.jdbc.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:mysql://localhost/shop?characterEncoding=utf-8&amp;autoReconnect=true
			</value>
		</property>
		<property name="username">
			<value>root</value>
		</property>
		<property name="password">
			<value>root</value>
		</property>

	</bean>
	<bean id="namedParameterJdbcTemplate"
		class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
		<constructor-arg ref="dataSource" />
	</bean>
	
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> 
		   <property name="transactionManager">
		      <ref bean="transactionManager" />
		   </property> 
		   <property name="transactionAttributes">
		    <props>
		     <prop key="find*">PROPAGATION_NEVER,readOnly</prop>
		     <prop key="get*">PROPAGATION_NEVER,readOnly</prop>
		     <prop key="load*">PROPAGATION_NEVER,readOnly</prop>
		     <prop key="query*">PROPAGATION_NEVER,readOnly</prop>
		     <prop key="is*">PROPAGATION_NEVER,readOnly</prop>
		     <prop key="has*">PROPAGATION_NEVER,readOnly</prop>
		     <prop key="exist*">PROPAGATION_NEVER,readOnly</prop>
		     <prop key="check*">PROPAGATION_NEVER,readOnly</prop>
		     <prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
		    </props>
		   </property>
		</bean>
		
		
		<!-- 自動代理 -->
		<bean id="autoproxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		   <!-- 能夠是Service或DAO層(最好是針對業務層*Service) -->
		   <property name="beanNames">
		    <list>
		     <value>*Service</value>
		    </list>
		   </property>
		   <property name="interceptorNames">
		    <list>
		        <value>transactionInterceptor</value>
		    </list>
		   </property>
		</bean> 
</beans>

 

 

 

 

 

 

3、經過DBColumnMapper、泛型封裝添加和修改方法

在項目使用中咱們能夠經過spring DBColumnMapper  獲取pojo全部字段,進而拼接insertSqlmysql

創建一個對象用來保存拼接的sql 和參數map spring

 

class InsertEntity{
		Map<String, Object> paramMap;
		String sql;
		public Map<String, Object> getParamMap() {
			return paramMap;
		}
		public void setParamMap(Map<String, Object> paramMap) {
			this.paramMap = paramMap;
		}
		public String getSql() {
			return sql;
		}
		public void setSql(String sql) {
			this.sql = sql;
		}		
	}

 

自定義columnMappersql

 

public class ColumnMapper {

	private String column;	
	private String filed;
	private Object value;

	public Object getValue() {
		return value;
	}

	public void setValue(Object value) {
		this.value = value;
	}

	public String getColumn() {
		return column;
	}

	public void setColumn(String column) {
		this.column = column;
	}

	public String getFiled() {
		return filed;
	}

	public void setFiled(String filed) {
		this.filed = filed;
	}
}

 

 

@Component
public class DBColumnMapper {

	private static Map<String, List<ColumnMapper>> mapper = new HashMap<String, List<ColumnMapper>>();
	
	private static final String UNDERLINE = "_";
	
	public <T> List<ColumnMapper> getColumnMapper(T obj) throws IllegalArgumentException, IllegalAccessException { 
		Class<?> clazz = obj.getClass();
		List<ColumnMapper> columnMapperList = mapper.get(clazz.getName());
		if(CollectionUtil.isEmpty(columnMapperList)) {
			columnMapperList = generateColumnMapper(obj);
			mapper.put(clazz.getName(), columnMapperList);
		}
		return columnMapperList;
	}

	private <T> List<ColumnMapper> generateColumnMapper(T obj) throws IllegalArgumentException, IllegalAccessException {
		List<ColumnMapper> columnMapperList = new ArrayList<ColumnMapper>();
		Class<?> clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for(Field field : fields) {
			field.setAccessible(true);
			String fieldName = field.getName();
	        DbIgnore dbIgnore = field.getAnnotation(DbIgnore.class);
			if(dbIgnore!=null) {
				logger.debug("the field[{}] has remarked as dbIgnore", fieldName);
			}
			if(!"serialVersionUID".equalsIgnoreCase(fieldName) && dbIgnore==null) {
				ColumnMapper columnMapper = new ColumnMapper();
				columnMapper.setFiled(fieldName); 
				columnMapper.setColumn(obtainColumn(fieldName));
				columnMapperList.add(columnMapper);
			} 
			field.setAccessible(false);
		}
		return columnMapperList;
	}

	private String obtainColumn(String fieldName) {
		StringBuffer builder = new StringBuffer();
		char[] charArray = fieldName.toCharArray();
		for(int index = 0; index < charArray.length; index++) {
			char ch = charArray[index];
			if(Character.isUpperCase(ch)) {
				if(index == 0) {
					builder.append(Character.toLowerCase(ch));
				} else {
					builder.append(UNDERLINE);
					builder.append(Character.toLowerCase(ch));
				}
			} else {
				builder.append(ch);
			}
		}
		return builder.toString();
	}
}

 

 

注入DBColumnMapper數據庫

 

 

@Autowired
private DBColumnMapper mapper;

 

 

泛型拼裝插入sqlapp

private <T> InsertEntity getInsertEntity(T obj, String tableName, String[] excludingNameArray) throws IllegalArgumentException, SecurityException, IllegalAccessException, NoSuchFieldException{
		InsertEntity insertEntity = new InsertEntity();
		Class<?> clazz = obj.getClass(); 
		
		List<ColumnMapper> columnMapperList = mapper.getColumnMapper(obj);
		
		StringBuffer insertSQL = new StringBuffer();
		insertSQL.append("INSERT INTO ");
		insertSQL.append(tableName);
		insertSQL.append("(");
		int count = 0;
		for(int index = 0; index < columnMapperList.size(); index++) {
			ColumnMapper mapper = columnMapperList.get(index);
			String filedName = mapper.getFiled();
			if(isIgnoreField(filedName, excludingNameArray)) { //這個方法就不提供了,這裏忽略了不須要保存的字段
				continue;
			}
			//若是字段值是空的,則不須要拼在腳本中,由於數據庫字段可能設置了非空的,或者設置了默認值的,因此插入null會有問題。
			if (mapper.getValue()==null) {
				continue;
			}
			
			if(count!=0 && index != columnMapperList.size()) {
				insertSQL.append(",");
			}			
			insertSQL.append(mapper.getColumn());
			count++;
		}
		insertSQL.append(")");
		insertSQL.append(" ");
		insertSQL.append("VALUES");
		insertSQL.append("(");
		
		count = 0;
		for(int index = 0; index < columnMapperList.size(); index++) {
			ColumnMapper mapper = columnMapperList.get(index);
			String filedName = mapper.getFiled();
			if(isIgnoreField(filedName, excludingNameArray)) {
				continue;
			}
			if (mapper.getValue()==null) {
				continue;
			}			
			if(count!=0 && index != columnMapperList.size()) {
				insertSQL.append(",");
			}				
			insertSQL.append(":");
			insertSQL.append(mapper.getFiled());
			count++;
		}
		insertSQL.append(")");
		
		Map<String, Object> paramMap = new HashMap<String, Object>();
		Field[] fields = clazz.getDeclaredFields();
		for(Field field : fields) {
			String fieldName = field.getName();
			if(!"serialVersionUID".equalsIgnoreCase(fieldName) && !isIgnoreField(fieldName, excludingNameArray)) {
				field.setAccessible(true);
				Object val = field.get(obj);
				Date now = new Date();
				if (field.getName().equals("createBy") && val == null) {
					val = 0;
				} else if (field.getName().equals("lastModifiedBy") && val == null) {
					val = 0;
				} else if (field.getName().equals("createTime") && val == null) {
					val = now;
				} else if (field.getName().equals("lastModifiedTime") && val == null) {
					val = now;
				}
				paramMap.put(field.getName(), val);
				field.setAccessible(false);
			}
		}
		String sql = insertSQL.toString(); 
		insertEntity.setParamMap(paramMap);
		//由於去掉了爲null的字段,因此拼裝sql的時候可能會出錯
		logger.info("insert sql={}", sql);
		insertEntity.setSql(sql);
		return insertEntity;
		
	}

 

 

4、插入並返回主鍵id

KeyHolder holder = new GeneratedKeyHolder();
		int rowNum = jdbcTemplate.update(insertEntity.getSql(), paramSource, holder);
		if(rowNum > 0) {
			return holder.getKey().intValue();
		} else {
			return null;
		}

 

 

 5、namedParameterJdbcTemplate  vs  jdbcTemplate

spring 後來提供的namedParameterJdbcTemplate   涵蓋了jdbcTemplate的全部用法,並支持數據可字段和pojo的自動映射,更妙的是namedParameterJdbcTemplate   會自動將數據庫的下劃線命名的字段自動轉爲pojo的駝峯命名(可能描述的不太恰當),下面是經過rowmapper的一種使用方法。ide

 

List<Product> products = jdbcTemplate.query(sql,paramMap, new BeanPropertyRowMapper<Product>(Product.class));

 

 

6、ResultSetExtractor 用法

這裏用反覆int舉了個例子,也能夠給自定義類添加ResultSetExtractor ui

int total = jdbcTemplate.query(pc.getCountSql(), paramMap, new ResultSetExtractor<Integer>() {
			@Override
			public Integer extractData(ResultSet rs) throws SQLException, DataAccessException {
				if (rs.next()) {
					return rs.getInt(1);
				}
				return 0;
			}

		});

 

 

 

7、orm vs jdbctemplate

 

喜歡jdbctemplate了this

 

8、經過註解來實如今insert的時候忽略數據庫中沒有的字段

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DbIgnore {
    boolean value() default true;
}
相關文章
相關標籤/搜索