问题背景
这里有一张表,只有一个字段status
表中数据如下:
status在业务逻辑中可能出现以下几种情况:
1:表示对象正常使用
2:表示对象已过期
0:表示对象已被删除
在MVC模式下,写sql语句操作数据库:
一般情况下,我们会用Page,List或Map封装执行sql后的数据用于业务操作。
public Page findPageListMap(final String sql,Page page,Object... arrayParameters);
public List<Map<String,Object>> findUniqueMapByArray(final String sql, Object... arraryParameters);
public Map findUniqueMapByArray(final String sql, Object... arrayParameters);
问题描述
当在ServiceImpl我们进行数据操作时:
public Page getStatusReturnPage() {
String sql = "select status from t_mysql_tinyint";
return baseDao.jdbcTemplate.findPageListMap(sql,page);
}
public List<Map<String, Object>> getStatusReturnList() {
String sql = "select status from t_mysql_tinyint";
return baseDao.jdbcTemplate.findUniqueMapByArray(sql,page);
}
public Map<String, Object> getStatusReturnMap() {
String sql = "select status from t_mysql_tinyint";
return baseDao.jdbcTemplate.findUniqueMapByArray(sql);
}
在Controller中分别调用三个方法
status1 = status.getStatusReturnPage();
status2 = status.getStatusReturnPage();
status2 = status.getStatusReturnPage();
System.out.print("status1: " + status1 + "\nstatus2: " + status2 + "\nstatus3: " + status3 );
打印出来的结果是 status1:2,status2:2,status3:true
这就有点奇怪了,Map返回的值竟然是布尔型!!
问题分析与解决
症状:
使用MySqlClient访问tinyint unsign 字段返回布尔值 true 和 false,但是实际上该字段存储值为1-255分析:
由于在Mysql中没有布尔类型值,MySqlClient在访问tinyint类型字段时默认作为布尔值使用。
解决:
1.在连接串中增加 Treat Tiny As Boolean=false 配置.
2.对应字段在SQL语句中*1,这样,读取出的字段值默认会被转换成int类型.
3.如果不是仅存取true和false,建议设计时使用int.
相关资料:
根据官方文档 10.1.1. Overview of Numeric Types ,在 MySql 中还没有严格的 bool 类型,但使用 TINYINT(1) 隐式用作 bool 类型,零作为false,而非零值(包括负数)作为true。但,这是不对称的。在执行逻辑比较时,true 等于 1,false 等于 0,但 true 不等于 2。这个文档显示的 MySql 5.0,其他后续版本是否有严格的 bool 类型未知。
在 MySql Connector/Net 中,遵循了上面这个约定,假如某个字段类型是 tinyint(1),则会被自动映射成 Boolean 类型。如果要禁用这个映射,可以在连接字符串中,配置 Treat Tiny As Boolean=false。这个选项的默认值是 true。参考 21.2.6. Connector/NET Connection String Options Reference 。没有查到这个选项从 Connector/Net 哪个版本开始支持,应该是 Connector/Net 5.x 之后都支持。