[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 值,标签获取的所有条件值都为 null,所有条件不成立,动态 sql 可以正常执行。
queryById(1L)方法执行时,parameterObject为 map,包含了id和param1两个 key 值。当获取标签中name的属性值时,进入((Map)parameterObject).get(name)方法中,map 中 key 不包含name,所以抛出异常。
queryById(1L,"1")方法执行时,parameterObject中包含id,param1,name,param2四个 key 值,id和name属性都可以获取到,动态 sql 正常执行。

作者:Esofar

出处:https://www.cnblogs.com/DCFV/p/18341090

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Duancf  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示