vlambda博客
学习文章列表

【经验与坑】MyBatis+MySQL 返回格式化日期以及动态表名和字段名

一.MyBatis + MYSQL 返回格式化日期


为了让后端的代码变得更加清爽,所以优化了 sql 语句。

且该表中的日期数据格式为 varchar 类型。


目标返回值:

原始返回值:

【经验与坑】MyBatis+MySQL 返回格式化日期以及动态表名和字段名


使用了 MYSQL 中的 DATE_FORMAT( ) 方法


DATE_FORMAT (date,format):date是一个合法的日期,format 是规定时间/日期的输出格式。


 所以我要一个 2020-01-02 格式的时间,写法就是 date_format(date,'%Y-%m-%d')


在 *mapper.xml 里面的写法:

 <sql id="DATE_FORMAT"> DATE_FORMAT(quackTime,'%Y-%m-%d') as qtime </sql>
<select id="getQuakeInfoByTime" resultType="java.lang.String"> select <include refid="DATE_FORMAT"></include> from ${dbTable} where quackTime between #{start_time} and #{end_time} </select>

通过 安插 一段 sql 脚本进行语法的拼接。


其中报错:

Error querying database. Cause: java.lang.UnsupportedOperationException

是因为我忘记更改 select 标签中的 返回值类型。

错误原因是 resultType=“java.util.List” ,这里应该改成:resultType=“java.lang.String”

这里 resultType 指的是 select 返回的每一条记录 的类型,而不是所有记录组成的类型。

这样就解决了这个问题。


二.动态表名和字段名


因为项目中的数据库中有几个结构完全相同,仅表名不同的数据表,(其实是完全可以写在一个表中的,加一列 area 区分就可以了)。那么就要进行动态的加载不同的表名来实现在不同的数据表中的操作。


动态 SQL 就是 MyBatis 的一个重要特性,MyBatis会在sql语句预编译之前对SQL进行动态解析,解析为一个 BoundSql 对象,也是在此处对sql进行动态处理。下面学习一下 #{} 和 ${} 的区别与用处。


#{ } 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符。

比如以下 SQL 语句

select * from user where name = #{name}

被解析为:

select * from user where name = ?

所以 #{} 会被解析为一个 参数占位符?


${ } 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换

比如以下SQL语句

select * from user where name = ${name}

当向name传 “han56” 时 ,会被解析为:

select * from user where name = "han56"

可以看到预编译之前的sql语句已经不包含变量name了。


#{}与${}的区别可以简单总结如下:

  • #{}将传入的参数当成一个字符串,会给传入的参数加一个双引号

  • ${}将传入的参数直接显示生成在sql中,不会添加引号

  • #{}能够很大程度上防止sql注入,${}无法防止sql注入

  • ${}一般用于传输数据库的表名、字段名等

  • 能用#{}的地方尽量别用${}

所以相对安全的 动态更改表名,字段名

 <select id="getUser" resultType="java.util.Map" parameterType="java.lang.String" statementType="STATEMENT"> select  ${columns} from ${tableName} where COMPANY_REMARK = ${company} </select>

要实现动态调用表名和字段名,就不能使用预编译了,需添加statementType="STATEMENT"


statementType:STATEMENT(非预编译),PREPARED(预编译)或CALLABLE中的任意一个,这就告诉 MyBatis 分别使用Statement,PreparedStatement或者CallableStatement。默认:PREPARED。这里显然不能使用预编译,要改成非预编译。


其次,sql里的变量取值是${xxx},不是#{xxx}。

  因为${}是将传入的参数直接显示生成sql,如${xxx}传入的参数为字符串数据,需在参数传入前加上引号,如:

String name = "han56";name = "'" + name + "'";