[Spring]Mybatis
Mybatis
作用#
- 数据库连接管理:MyBatis可以自动管理数据库连接,避免了手动创建和关闭数据库连接的繁琐过程。
- SQL语句生成:MyBatis可以根据Java对象和数据库表结构自动生成SQL语句,避免手写SQL语句的麻烦和错误。
- 参数映射:MyBatis可以将Java对象中的属性值自动映射到SQL语句中的占位符,从而实现参数的传递。
- 结果集映射:MyBatis可以将SQL查询结果集映射到Java对象中,从而实现数据的转换和处理。
- 缓存机制:MyBatis支持缓存机制,可以提高数据访问的性能和效率。
#{} 和 ${}#
1、传入的参数在SQL中显示不同
#{} 将传入的参数(数据)在SQL中显示为字符串,会对自动传入的数据加一个双引号。
「对自动传入的数据加一个双引号」
例:使用以下SQL语句
SELECT id,name FROM student WHERE id =#{id};
//当我们传递的参数id为 "1" 时,上述 SQL 的解析为:
SELECT id,name FROM student WHERE id ="1";
${} 将传入的参数(数据)直接显示生成在SQL中
例:使用以下SQL语句
SELECT id,name FROM student WHERE id =${id};
//当我们传递的参数id为 "1" 时,上述 sql 的解析为:
SELECT id,name FROM student WHERE id =1;
2、#{}可以防止SQL注入的风险(语句的拼接);但${}无法防止SQL注入。
3、${}方式一般用于传入数据库对象,例如:表名用参数传递进SQL。
4、大多数情况下还是经常使用#{},一般能用#{}的就别用${};但有些情况下必须使用${},例:MyBatis排序时使用ORDER BY动态参数时需要注意,得用${}而不是#{}。
5、#{} 的参数替换是发生在 DBMS 中,而 ${} 则发生在动态解析过程中。
Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?#
注:这道题也是京东面试官面试我被问的。
最佳实践中,通常一个 xml 映射文件,都会写一个 Dao 接口与之对应。
Dao 接口就是人们常说的 Mapper 接口,
接口的全限名,就是映射文件中的 namespace 的值,
接口的方法名,就是映射文件中 MappedStatement 的 id 值,
接口方法内的参数,就是传递给 sql 的参数。
Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MappedStatement ,
举例:com.mybatis3.mappers.StudentDao.findStudentById ,可以唯一找到 namespace 为 com.mybatis3.mappers.StudentDao 下面 id = findStudentById 的 MappedStatement 。在 MyBatis 中,每一个 <select>、 <insert>、 <update>、 <delete> 标签,都会被解析为一个 MappedStatement 对象。
Dao 接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略
。
Dao 接口里的方法可以重载,但是 Mybatis 的 xml 里面的 ID 不允许重复。(这句话是有问题的,下面我们详细解释有什么问题)
Mybatis 版本 3.3.0,亲测如下:
/**
* Mapper接口里面方法重载
*/
public interface StuMapper {
List<Student> getAllStu();
List<Student> getAllStu(@Param("id") Integer id);
}
然后在 StuMapper.xml 中利用 Mybatis 的动态 sql 就可以实现。
<select id="getAllStu" resultType="com.pojo.Student">
select * from student
<where>
<if test="id != null">
id = #{id}
</if>
</where>
</select>
能正常运行,并能得到相应的结果,这样就实现了在 Dao 接口中写重载方法。
Mybatis 的 Dao 接口可以有多个重载方法,但是多个接口对应的映射必须只有一个,否则启动会报错。
相关 issue:更正:Dao 接口里的方法可以重载,但是 Mybatis 的 xml 里面的 ID 不允许重复!
。
Dao 接口的工作原理是 JDK 动态代理,MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,代理对象 proxy 会拦截接口方法,转而执行 MappedStatement 所代表的 sql,然后将 sql 执行结果返回。
测试过后,发现几个问题,这里其实并不是真正意义上的重载,楼主亲测的可行的重载方法,存在一个很大的问题,就是定义多个有参方法的时候,比如:
User getById();
User getById(@param("id) Integer id)
User getById(@param("id) Integer id,@param("name) String name)
上面你的这种场景下,去调用无参方法是可以成功的,但是调用 2方法,是失败的,会报错 Parameter 'name' not found. Available parameters are [id, param1],
也就是意味着,只能存在一个无参方法和一个有参方法,其实很鸡肋,并不提倡这么使用,四不像了。
结论是:dao中的接口不可可以重载的。
补充:
Dao 接口方法可以重载,但是需要满足以下条件:
仅有一个无参方法和一个有参方法
多个有参方法时,参数数量必须一致。且使用相同的 @Param ,或者使用 param1 这种
测试如下:
PersonDao.java
Person queryById();
Person queryById(@Param("id") Long id);
Person queryById(@Param("id") Long id, @Param("name") String name);
PersonMapper.xml
<select id="queryById" resultMap="PersonMap">
select
id, name, age, address
from person
<where>
<if test="id != null">
id = #{id}
</if>
<if test="name != null and name != ''">
name = #{name}
</if>
</where>
limit 1
</select>
org.apache.ibatis.scripting.xmltags. DynamicContext. ContextAccessor#getProperty 方法用于获取
public Object getProperty(Map context, Object target, Object name) {
Map map = (Map) target;
Object result = map.get(name);
if (map.containsKey(name) || result != null) {
return result;
}
Object parameterObject = map.get(PARAMETER_OBJECT_KEY);
if (parameterObject instanceof Map) {
return ((Map)parameterObject).get(name);
}
return null;
}
parameterObject 为 map,存放的是 Dao 接口中参数相关信息。
((Map)parameterObject).get(name) 方法如下
public V get(Object key) {
if (!super.containsKey(key)) {
throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + keySet());
}
return super.get(key);
}
queryById()方法执行时,parameterObject为 null,getProperty方法返回 null 值,
queryById(1L)方法执行时,parameterObject为 map,包含了id和param1两个 key 值。当获取
queryById(1L,"1")方法执行时,parameterObject中包含id,param1,name,param2四个 key 值,id和name属性都可以获取到,动态 sql 正常执行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?