解决MyBatis中常见的错误
传递多个参数时出现的错误
dao层中的方法只传递一个参数,但需要传递多个参数时会出现什么问题呢?
dao接口内容:
public interface RoleDao {
//根据role_name和role_code查询用户
public Role selectByNameAndCode(String name,String code);
}
对应接口的映射文件:
<select id="selectByNameAndCode" resultType="com.hrc.entity.Role"> select * from t_role where role_name = #{name} and role_code=#{code} </select>
测试代码:
public class RoleTest {
@Test
public void queryTest() throws Exception{
//读取 MyBatis配置文件资源
//import org.apache.ibatis.io.Resources; 注意这里导入的包必须是ibatis下的
Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
//创建SqlSessionFactory工厂(根据读取mybatis配置文件进行创建)
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsReader);
//开启SqlSession会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过映射关系,获取映射文件中对应的接口
RoleDao roleDao = sqlSession.getMapper(RoleDao.class);
//通过接口调用相关查询方法(注意一点:数据库中式存在这名角色的信息)
Role role = roleDao.selectByNameAndCode("老师", "teacher");
//输出结果
System.out.println("role = " + role);
}
}
结果展示:
原因是:MyBatis中如何传递多个参数时,默认第一个参数为param1或arg0后面参数依次类推。
解决方法:
使用注解@Param("起别名"):通过给参数起别名的方式
例如:
效果展示:
实现模糊查询
模糊查询的sql语句为:
select * from 表名 where 列名 like '';
注意:
%:表示匹配0个或多个字符
_:表示匹配一个字符
实现模糊查询拥有两种方法解决:
①使用MySQL中函数concat()
语法:
concat(字符串a,字符串b,......,字符串n)
举个例子:
dao接口中的方法:
public interface RoleDao {
//根据role_name模糊查询用户
public List<Role> likeByName(String name);
}
对应其映射文件内容:
<select id="likeByName" resultType="com.hrc.entity.Role">
select * from t_role where role_name like concat('%',#{name},'%')
</select>
效果展示:
通过模糊查询,找到姓名存在管理员的人有三个。
②使用${}实现字符串拼接
语法:
${'\'%'+值+'%\''}
举个例子:
dao对应的映射文件内容:
效果展示:
这里出现的${}与#{}的区别
${}:一般是用于字符串拼接的,而字符串拼接会出现一个问题(SQL注入)
#{}:使用占位符的方式,mybatis通过PrepareStatement完成占位符赋值,可以有效的防止sql注入安全问题。
解决MyBatis映射文件中出现的特殊字符
由于MyBatis中存在一些特殊含义的字符比如:>,<,',&
要如何解决这些特殊字符呢?
方法一:使用这些字符的转义字符
举个例子:
dao接口内容:
public interface StudentDao {
//查询年龄在min与max之间的学生
public List<Student> queryByAge(@Param("min") Integer min ,@Param("max") Integer max);
}
对应其映射文件内容:
效果展示:
方法二:使用<![CDATA[sql]]>实现
举个例子:
接口对应其映射文件内容:
<select id="queryByAge" resultType="com.hrc.entity.Student"> <![CDATA[ select * from t_student where age >= #{min} and age <=#{max} ]]]> </select>
效果展示:
结果与之前的一样。
列名和属性名不一致
之前说过,数据库中列名要和属性名一致,否则会出现数据库列内容映射不到实体类的属性值。
这里我们可以使用两种方法来解决这个问题:
这里我将实体类Role中部分属性与数据库中列名不一致:
@Data @NoArgsConstructor @AllArgsConstructor public class Role { //角色id与数据库中列名不一致 private Integer rid; //角色的姓名与数据库中列名不一致 private String name; //角色的编码与数据库中列名不一致 private String code; //角色的描述与数据库中列名一致 private String description; }
方法一:给查询出来的数据库列名起别名
举个例子:
接口对应的映射器内容:
效果展示:
方法二:使用resultMap进行映射
举个例子:
效果展示:
结果与第二种方法的一致。
测试代码:
public class RoleTest {
@Test
public void queryTest() throws Exception{
//读取 MyBatis配置文件资源
//import org.apache.ibatis.io.Resources; 注意这里导入的包必须是ibatis下的
Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
//创建SqlSessionFactory工厂(根据读取mybatis配置文件进行创建)
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsReader);
//开启SqlSession会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过映射关系,获取映射文件中对应的接口
RoleDao roleDao = sqlSession.getMapper(RoleDao.class);
//通过接口调用相关查询方法(注意一点:数据库中式存在这名角色的信息)
Role role = new Role(null,"普通用户","user","一个普通的用户");
System.out.println("添加前的role: " + role);
roleDao.insertRole(role);
sqlSession.commit();
System.out.println("添加后的role: " + role);
}
}
效果展示:
控制台的内容:
数据库的内容: