给spring jdbctemplate加上一层“绮丽外衣”-动态SQL&&SQL语句以文件存放

给spring jdbctemplate加上一层“华丽外衣”-动态SQL&&SQL语句以文件存放

用hibernate用得多了,忽然怀念起自己直接写sql 的轻巧类库了。

开源的类库中,需要写sql常用的有spring jdbc ,apache的dbutil , MyBatis。看过MyBatis文档,写过demo, 相对于hibernate这个强大的ORM工具,MyBatis可控性更好,然而今天它不主角,今天的主角是spring jdbc.



spring jdbc 当我一接触到的时候,从此深深爱上了这个小巧的家伙:简单而优雅的API,配上spring本身的声名式事务!这就是一把小巧的神器!

然而随着我深入的了解,让我不爽的是SQL语句写在JAVA代码中,想要动态SQL自己拼字符串吧!

但是这又有什么的?我把SQL语句放在外部文件,然后把它读出来就行了。

有这想法第一步想到的是:

利用Spring注入功能,把SQL注入到bean中去,但是想想又不合适,不喜欢用xml方式配置spring bean ,如果每个 bean都注入几条SQL,不是所有要用SQL的bean都要写在xml文件吗?

这个办法不是一个优雅的解决办法,那创建一个类,利用spring注入功能,将相关的值注入到map属性中,尝试了一下,所有的sql都丢到一个文件多不优雅!还是自己动手来读吧,dom4j读xml很简单,上代码:



public class SQLBuilder {

private static Logger logger = LoggerFactory.getLogger(SQLBuilder.class);

private Map<String, String> sqlContainer = null;

private String sqlFilePath = "systemSql.xml";

public SQLBuilder() {

initSqlContainer();
}

public SQLBuilder(String sqlFilePath) {

this.sqlFilePath = sqlFilePath;
initSqlContainer();
}

public String getSql(String key) {
String sql = sqlContainer.get(key);
if (sql == null || "".equals(sql))
logger.warn("不存在该SQL语句");
if (logger.isDebugEnabled()) {
logger.debug("SQL:" + sql);
}
return sql;
}

public String getDynamicalSql(String key, Map<String, ?> param) {
String sql = sqlContainer.get(key);

return VelocityUtils.render(sql, param);
}


@SuppressWarnings("unchecked")
private void initSqlContainer() {
sqlContainer = new ConcurrentHashMap<String, String>();
if (sqlFilePath == null || "".equals(sqlFilePath)) {
throw new NullPointerException("sql语句文件不能为空!");
}
String[] files = sqlFilePath.split(";");
for (String file : files) {
readSQLFromFile(file);
}
}

private void readSQLFromFile(String fileName) {
InputStream ips = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(fileName);
Document document = null;
SAXReader saxReader = new SAXReader();
try {
document = saxReader.read(ips);
} catch (DocumentException e) {
logger.error("读取系统中用到的SQL 语句XML出错");
throw new RuntimeException("读取sql语句XML文件出错:" + e.getMessage());
}
Element root = document.getRootElement();
List<Element> sqlElements = root.selectNodes("//sqlElement");
String key;
for (Element sql : sqlElements) {
key=sql.attribute("key").getValue();
if(sqlContainer.containsKey(key)){
logger.warn("key值:"+key+"重复");
}
sqlContainer.put(key, sql.getText());

}

if (ips != null) {
try {
ips.close();
} catch (IOException e) {
logger.error("关闭输入流出错:" + e.getMessage());
}
}
}

public void setSqlFilePath(String sqlFilePath) {
this.sqlFilePath = sqlFilePath;
}

@Override
protected void finalize() throws Throwable {
super.finalize();
if (sqlContainer != null) {
sqlContainer.clear();
sqlContainer = null;
}

}

}


模板技术用过freemarker ,velocity 我喜欢velocity多点,直接拿springside 里面工具类生成动态SQL

/**
* 使用Velocity生成内容的工具类.
*
* @author calvin
*/
public class VelocityUtils {

static {
try {
Velocity.init();
} catch (Exception e) {
throw new RuntimeException("Exception occurs while initialize the velociy.", e);
}
}

/**
* 渲染内容.
*
* @param template 模板内容.
* @param model 变量Map.
*/
public static String render(String template, Map<String, ?> model) {
try {
VelocityContext velocityContext = new VelocityContext(model);
StringWriter result = new StringWriter();
Velocity.evaluate(velocityContext, result, "", template);
return result.toString();
} catch (Exception e) {
throw new RuntimeException("Parse template failed.", e);
}
}
}

<?xml version="1.0" encoding="UTF-8"?>
<sqls>
<sqlElement key="queryUser">
<![CDATA[

select * from t_userInfo

]]>
</sqlElement>

<sqlElement key="insertUser">
<![CDATA[

insert into t_userInfo(sex,age,userName,address,contactNumber,mobilePhone)
values(:sex,:age,:userName,:address,:contactNumber,:mobilePhone)

]]>
</sqlElement>
<sqlElement key="updateUser">
<![CDATA[

update t_userInfo set userName=:userName where userID=:userID

]]>
</sqlElement>

<sqlElement key="deleteUser">
<![CDATA[

delete from t_userInfo where userID=:userID

]]>

</sqlElement>


<sqlElement key="search">

<![CDATA[

select * from t_userinfo

#if( $user.userName !="")
where userName like :userName
#end

]]>

</sqlElement>

</sqls>

调用:可以自己创建对象,或者将SQLBuilder 放到spring容器中,让spring 管理bean

SQLBuilder是线程安全的建议仅创建一个实例,减少读取SQL语句文件 的IO消耗!


public class JdbcTest {

@Resource
DataSource dataSource;

@Resource
SQLBuilder sqlBuilder;

private NamedParameterJdbcOperations jdbcTemplate;

public JdbcTest() {
// jdbcTemplate = getJdbcTemplate();
}

public NamedParameterJdbcOperations getJdbcTemplate() {
return jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);

}



@Transactional
public void deleteUser(Map<String, Integer> param) {
getJdbcTemplate().update(sqlBuilder.getSql("deleteUser"), param);
}

}


【转载地址】http://www.myexception.cn/database/424711.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值