这里写代码片使用Mybatis开发持久层,庞大的xml配置文件提供了强大的功能,但是sql语句需要在xml文件中进行配置,并且必须遵循一定的规则。
现在可以使用注解开发来代替xml配置文件。具体的流程就不再赘述,可以查看《Java持久化之myBatis3》,此书大体介绍了注解开发,本文就实际开发中遇到的问题进行表述。
1.#{}和${}使用出错
@Select("select ad.*,ac.name as name,ac.acsid from acs_door ad left join acs_server ac on ad.serverid = ac.id where #{codingTerm}")
List<AcsDoorBean> getList(@Param("codingTerm")String codingTerm);
codingTerm 是一个和权限有关的字符串,”coding like ‘%33%’”,
当使用#{}进行占位符操作时,junit单元测试控制台打印
==>Preparing: select ad.*,ac.name as name,ac.acsid from acs_door ad left join acs_server ac on ad.serverid = ac.id where ?
==> Parameters: ad.coding like '%33%'(String)
<== Total: 0
不会抛异常,sql语句没问题,参数绑定也没问题,但是无法从数据库或得正确的数据。
所以考虑到#{}是提供占位符的操作而${}可以用来进行sql拼接,而codingTerm不是表中的字段,和实体类无法形成关系映射,所以不能使用占位符,进行替换后控制台打印如下,并且可以正常查出需要的数据。#{}就相当于sql语句的“?”进行占位操作。
==> Preparing: select ad.*,ac.name as name,ac.acsid from acs_door ad left join acs_server ac on ad.serverid = ac.id where ad.coding like '%33%'
==> Parameters:
<== Columns: id, serverid, deviceid, doorid, doorname, name, comment, doorstate, doorcontrolstate, coding, emapLeft, emapTop, emapId, name, acsid
<== Row: 1, 1, 33, null, null, null, null, null, null, 33, null, null, null, null, null
<== Row: 2, 2, 33, null, null, null, null, null, null, 33, null, null, null,
<== Total: 3
**当使用${}进行拼接式codingTerm参数钱必须加@Param(“codingTerm”)注解,否则会报错
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'codingTerm' in 'class java.lang.String'
@Select("select id from acs_door where doorname=?")
int isNameExistForAdd(@Param("doorname")String doorname);
当输出的参数id类型为int,返回值类型也是int,代码没问题,junit运行不报错,但得不到自己想要的结果,因为id是表中字段但没有映射的类的去封装,所以如果要返回值进行判断的话需改成
@Select("select count(id) from acs_door where doorname=?")
int isNameExistForAdd(@Param("doorname")String doorname);
这样就能返回你所需要的int类型的值进行下一步的判断。
还有一个原因就是当你查询的对象id为null时,int也没办法作为返回值类型。
@SelectProvider(type=AcsSqlProvider.class,method = "getAlarmListSql")
List<AcsAlarmBean> getAlarmList(AcsAlarmSearchBean alarmBean,String codingTerm, String sqlTermDeviceidDoorAlarm);
ACSSQLProvider类中提供sql语句,可以通过继承SqlBuilder类拼接规范sql,但是亲自测试不继承也能获取参数以及返回sql语句
public String getAlarmListSql(Map map)
{
AcsAlarmSearchBean searchBean = (AcsAlarmSearchBean) map.get("searchBean");
StringBuilder sql = new StringBuilder()
.append("select aa.*, ad.doorname as doorname from acs_alarm aa")
.append(" left join acs_door ad on ad.deviceid=aa.deviceid")
.append(" where ${codingTerm}")
.append(" and aa.deviceid in ${sqlTermDeviceidDoorAlarm}");
if ((searchBean.getDeviceid() != null) && (!searchBean.getDeviceid().equals("")))
{
sql.append(" and aa.deviceid=#{searchBean.deviceid}");
}
if (searchBean.getAlarmtype() != null)
{
sql.append(" and aa.alarmtype=#{alarmtype}");
}
if (searchBean.getAlarmstate() != null)
{
sql.append(" and aa.alarmstate=#{alarmstate}");
}
if ((searchBean.getAlarmTimeBegin() != null) && (searchBean.getAlarmTimeEnd() != null))
{
sql.append(" and alarmtime>=#{alarmTimeBegin} and alarmtime);
}
sql.append(" order by alarmtime desc ");
return sql.toString();
}
当出现两个 时无法有效的拼接,可以先获取到具体参数的值,在进行append添加,不使用 {};如下
public String getAlarmListSql(Map<String, Object> map)
{
AcsAlarmSearchBean searchBean = (AcsAlarmSearchBean) map.get("searchBean");
String codingTerm = (String) map.get("codingTerm");
String sqlTermDeviceidDoorAlarm = (String) map.get("sqlTermDeviceidDoorAlarm");
StringBuilder sql = new StringBuilder()
.append("select aa.*, ad.doorname as doorname from acs_alarm aa")
.append(" left join acs_door ad on ad.deviceid=aa.deviceid")
.append(" where ").append(codingTerm)
.append(" and aa.deviceid in ").append(sqlTermDeviceidDoorAlarm);
还有一个问题,当通过#{alarmtype}来获取searchBean的alarmtype属性时会报绑定错误org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'alarmtype' not found. Available parameters are [sqlTermDeviceidDoorAlarm, param1, param2, codingTerm, param3, searchBean]
,必须用#{searchBean.alarmtype}来获取参数,参数绑定时无法识别#{alarmtype}的来源,必须指定。