mybatis错误之配置文件属性配置问题
在mybatis的配置文件SqlMapConfig.xml中,可以在开始的地方先加载一个properties节点,用来定义属性变量。
1 <!-- 加载属性文件 --> 2 <properties resource="db.properties"> 3 <!--properties中还可以配置一些属性名和属性值 --> 4 <!-- <property name="jdbc.driver" value=""/> --> 5 </properties>
然后可以在后面的节点中引用变量:
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=
value=m
SqlMapConfig
1 <!-- 和spring整合后 environments配置将废除--> 2 <environments default="development"> 3 <environment id="development"> 4 <!-- 使用jdbc事务管理,事务控制由mybatis--> 5 <transactionManager type="JDBC" /> 6 <!-- 数据库连接池,由mybatis管理--> 7 <dataSource type="POOLED"> 8 <property name="driver" value="${jdbc.driver}" /> 9 <property name="url" value="${jdbc.url}" /> 10 <property name="username" value="${jdbc.username}" /> 11 <property name="password" value="${jdbc.password}" /> 12 </dataSource> 13 </environment> 14 </environments>
但是,这涉及到几个问题,首先就是加载顺序,后者的变量会覆盖先加载的?看教程是这样说的:
properties特性:
注意:
MyBatis 将按照下面的顺序来加载属性:
在 properties 元素体内定义的属性首先被读取。
然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
最后读取parameterType传递的属性,它会覆盖已读取的同名属性。
建议:
不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。
在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX
举例来说:
- 在db.properties中定义了value=m
- 在mybat配置mapper里,SqlMapConfig.xml中设置mapper文件为:
1 <!-- 加载 映射文件 --> 2 <mappers> 3 <mapper resource="mapper/UserMapper.xml"/> 4 </mappers>
3. 编写接口:UserMapper.java
1 package cn.mrf.mybatis.mapper; 2 3 4 import java.util.List; 5 6 import cn.mrf.mybatis.po.User; 7 8 /** 9 * 10 * @ClassName: UserDao 11 * @Description: mapper接口:用户管理 12 * @author mrf 13 * @date 2015-9-19 下午05:48:49 14 * 15 */ 16 public interface UserMapper { 17 18 19 //根据id查询用户信息 20 public User findUserById(int id) throws Exception; 21 22 //根据用户名查询用户列表 23 public List<User> findUserByName(String name) throws Exception; 24 25 //添加用户信息 26 public void insertUser(User user) throws Exception; 27 28 //删除用户信息 29 public void deleteUser(int id) throws Exception; 30 31 //更新用户信息 32 public void updateUser(User user) throws Exception; 33 34 }
4. 配置UserMapper.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 6 <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 7 注意:使用mapper代理方法开发,namespace有特殊重要的作用 8 --> 9 <mapper namespace="cn.mrf.mybatis.mapper.UserMapper"> 10 11 <!-- 在 映射文件中配置很多sql语句 --> 12 <!-- 需求:通过id查询用户表的记录 --> 13 <!-- 通过 select执行数据库查询 14 id:标识 映射文件中的 sql 15 将sql语句封装到mappedStatement对象中,所以将id称为statement的id 16 parameterType:指定输入 参数的类型,这里指定int型 17 #{}表示一个占位符号 18 #{id}:其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称 19 20 resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。 21 --> 22 <select id="findUserById" parameterType="int" resultType="cn.mrf.mybatis.po.User"> 23 SELECT * FROM USER WHERE id=#{value} 24 </select> 25 26 <!-- 根据用户名称模糊查询用户信息,可能返回多条 27 resultType:指定就是单条记录所映射的java对象 类型 28 ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中。 29 使用${}拼接sql,引起 sql注入 30 ${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value 31 --> 32 <select id="findUserByName" parameterType="java.lang.String" resultType="cn.mrf.mybatis.po.User"> 33 SELECT * FROM USER WHERE username LIKE '%${value}%' 34 </select> 35 </mapper>
5. 编写mapper代理测试用例UserMapperTest.java
1 package cn.mrf.mybatis.mapper; 2 3 4 import java.io.InputStream; 5 import java.util.List; 6 7 import org.apache.ibatis.io.Resources; 8 import org.apache.ibatis.session.SqlSession; 9 import org.apache.ibatis.session.SqlSessionFactory; 10 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 11 import org.junit.Before; 12 import org.junit.Test; 13 14 import cn.mrf.mybatis.po.User; 15 16 import com.sun.istack.internal.Builder; 17 18 public class UserMapperTest { 19 20 private SqlSessionFactory sqlSessionFactory; 21 22 @Before 23 public void setUp() throws Exception { 24 // 创建sqlSessionFactory 25 // mybatis配置文件 26 String resource = "SqlMapConfig.xml"; 27 // 得到配置文件流 28 InputStream inputStream = Resources.getResourceAsStream(resource); 29 // 创建会话工厂,传入mybatis的配置文件信息 30 sqlSessionFactory = new SqlSessionFactoryBuilder() 31 .build(inputStream); 32 33 } 34 35 @Test 36 public void testFindUserByName() throws Exception{ 37 SqlSession sqlSession = sqlSessionFactory.openSession(); 38 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 39 List<User> users = userMapper.findUserByName("小军"); 40 System.out.println(users); 41 sqlSession.close(); 42 43 } 44 45 }
5.结果:
1 DEBUG [main] - Opening JDBC Connection 2 DEBUG [main] - Created connection 423250256. 3 DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@193a4950] 4 DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE username LIKE '%m%' 5 DEBUG [main] - ==> Parameters: 6 DEBUG [main] - <== Total: 1 7 [User [id=1, username=mrf, sex=男, birthday=Sat Feb 23 00:00:00 CST 1991, address=北京]] 8 DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@193a4950] 9 DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@193a4950] 10 DEBUG [main] - Returned connection 423250256 to pool.
6.分析:
可以看出,本来是根据用户名查找用户,输入了用户名为小军,而实际上,系统读取的用户名为m.
也就是说,系统没有读取parameterType的值,或者被覆盖。
那么,问题是,教程说最后读取parameterType并覆盖、如果这样,最后应该读取的小军才对。实际却是m.顺序有疑问了。
好吧,因为parameterType中并没有这个值,所以没有覆盖。
关注我的公众号