一、前言
项目使用jdbctemplate已经一段时间了,对于jdbcTemplate的使用有了一些小小心得,这里总结后跟大家分享下。
二、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&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>
三、通过DBColumnMapper、泛型封装添加和修改方法
在项目使用中我们可以通过spring DBColumnMapper 获取pojo所有字段,进而拼接insertSql
建立一个对象用来保存拼接的sql 和参数map
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;
}
}
自定义columnMapper
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;
泛型拼装插入sql
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;
}
四、插入并返回主键id
KeyHolder holder = new GeneratedKeyHolder();
int rowNum = jdbcTemplate.update(insertEntity.getSql(), paramSource, holder);
if(rowNum > 0) {
return holder.getKey().intValue();
} else {
return null;
}
五、namedParameterJdbcTemplate vs jdbcTemplate
spring 后来提供的namedParameterJdbcTemplate 涵盖了jdbcTemplate的所有用法,并支持数据可字段和pojo的自动映射,更妙的是namedParameterJdbcTemplate 会自动将数据库的下划线命名的字段自动转为pojo的驼峰命名(可能描述的不太恰当),下面是通过rowmapper的一种使用方法。
List<Product> products = jdbcTemplate.query(sql,paramMap, new BeanPropertyRowMapper<Product>(Product.class));
六、ResultSetExtractor 用法
这里用反复int举了个例子,也可以给自定义类添加ResultSetExtractor
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;
}
});
七、orm vs jdbctemplate
喜欢jdbctemplate了
八、通过注解来实现在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;
}
来源:oschina
链接:https://my.oschina.net/u/1265394/blog/420760