八、MyBatis小技巧

本文围绕MyBatis展开,介绍了#{}和${}的区别,#{}可避免SQL注入,优先使用,而在特定场景如拼接关键字、表名等需用${}。还阐述了MyBatis别名机制、mappers标签的使用,以及插入数据时获取自动生成主键的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. #{} 和 ${} 的区别

  • #{}: 底层使用PreparedStatement。特点:先进行SQL语句的编译,然后给SQL语句的占位符问号?传值。可以避免SQL注入的风险。

  • ${}:底层使用Statement。特点:先进行SQL语句的拼接,然后再对SQL语句进行编译。存在SQL注入的风险。

    优先使用#{},这是原则。避免SQL注入的风险。

    1.1什么时候使用${}

    CarMapper.java

    /**
    * 查询所有的汽车信息。然后通过asc升序,desc降序。
    * @param ascOrDesc
    * @return
    */
    List<Car> selectAllByAscOrDesc(String ascOrDesc);
    

    CarMapper.xml

    <select id="selectAllByAscOrDesc" resultType="com.powernode.mybatis.pojo.Car">
            select
                id,
                car_num as carNum,
                brand,
                guide_price as guidePrice,
                produce_time as produceTime,
                car_type as carType
            from
                t_car
            order by
            	<!--produce_time #{ascOrDesc}-->
                produce_time ${ascOrDesc}
        </select>
    

    CarMapperTest

    @Test
        public void testSelectAllByAscOrDesc(){
            SqlSession sqlSession = SqlSessionUtil.openSession();
            CarMapper mapper = sqlSession.getMapper(CarMapper.class);
            List<Car> cars = mapper.selectAllByAscOrDesc("desc");
            cars.forEach( car -> System.out.println(car));
            sqlSession.close();
        }
    
  • #{}的执行结果:
    select id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType from t_car order by produce_time 'asc'

  • ${}的执行结果:
    select id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType from t_car order by produce_time asc

    如果需要SQL语句的关键字放到SQL语句中,只能使用${},因为#{}是以值的形式放到SQL语句当中的。

    1.2 向SQL语句当中拼接表名,就需要使用${}

    业务当中,可能会存在分表存储数据的情况。因为一张表存的话,数据量太大。查询效率比较低。
    可以将这些数据有规律的分表存储,这样在查询的时候效率就比较高。因为扫描的数据量变少了。
    日志表:专门存储日志信息的。如果t_log只有一张表,这张表中每一天都会产生很多log,慢慢的,这个表中数据会很多。
    怎么解决问题?
    可以每天生成一个新表。每张表以当天日期作为名称,例如:
    t_log_20220901
    t_log_20220902

    <select id="selectAllByTable" resultType="com.powernode.mybatis.pojo.Log">
            select * from t_log_${date}
    </select>
    
    1.3.批量删除:一次删除多条记录。

    批量删除的SQL语句有两种写法:
    第一种or:delete from t_car where id=1 or id=2 or id=3;
    第二种int:delete from t_car where id in(1,2,3);

    应该采用${}的方式:
    delete from t_car where id in(${ids});

    1.4.模糊查询:like

    需求:根据汽车品牌进行模糊查询
    select * from t_car where brand like ‘%奔驰%’;

    第一种方案:
    '%${brand}%'
    第二种方案:concat函数,这个是mysql数据库当中的一个函数,专门进行字符串拼接
    concat('%',#{brand},'%')
    第三种方案:比较鸡肋了。可以不算。
    concat('%','${brand}','%')
    第四种方案:
    "%"#{brand}"%"

    <select id="selectByBrandLike" resultType="com.powernode.mybatis.pojo.Car">
            select
            id,
            car_num as carNum,
            brand,
            guide_price as guidePrice,
            produce_time as produceTime,
            car_type as carType
            from
            t_car
            where
            <!--brand like '%${brand}%'-->
            <!--brand like concat('%',#{brand},'%')-->
            <!--brand like concat('%','${brand}','%')-->
            brand like "%"#{brand}"%"
        </select>
    

2. 关于MyBatis中别名机制:

<!--起别名-->
<typeAliases>
    <!--
        type:指定给哪个类型起别名
        alias:指定别名
        别名不区分大小写
        alias属性可以省略,别名就是类的简名
    -->
    <typeAlias type="com.powernode.mybatis.pojo.CarMapper" alias="car"/>
    <!--将包下的所有类全部起别名,别名就是类简名,不区分大小写-->
    <package name="com.powernode.mybatis.pojo"/>
</typeAliases>

所有别名不区分大小写。
namespace不能使用别名机制。

6. mybatis-config.xml文件中的mappers标签。

<mapper resource="CarMapper.xml"/> 要求类的根路径下必须有:CarMapper.xml
<mapper url="file:///d:/CarMapper.xml"/> 要求在d:/下有CarMapper.xml文件
<mapper class="全限定接口名,带有包名"/>

  • mapper标签的属性可以有三个:

    • resource:这种方式是从类的根路径下开始查找资源。采用这种方式的话,配置文件需要放到类路径当中才行。
    • url: 这种方式是一种绝对路径的方式,这种方式不要求配置文件必须放到类路径当中,哪里都行,只要提供一个绝对路径就行。这种方式使用极少,因为移植性太差。
    • class: 这个位置提供的是mapper接口的全限定接口名,必须带有包名的。
    • 思考:mapper标签的作用是指定SqlMapper.xml文件的路径,指定接口名有什么用呢?
      <mapper class="com.powernode.mybatis.mapper.CarMapper"/>
      如果你class指定是:com.powernode.mybatis.mapper.CarMapper
      那么mybatis框架会自动去com/powernode/mybatis/mapper目录下查找CarMapper.xml文件。
      注意:也就是说:如果你采用这种方式,那么你必须保证CarMapper.xml文件和CarMapper接口必须在同一个目录下。并且名字一致。
      CarMapper接口-> CarMapper.xml
  • package:将包内的映射器接口实现全部注册为映射器

提醒:
在IDEA的resources目录下新建多重目录的话,必须是这样创建:
com/powernode/mybatis/mapper
不能这样:
com.powernode.mybatis.mapper

<mappers>
    <!--根路径下查找CarMapper.xml文件-->
    <mapper resource="CarMapper.xml"/>
    <!--绝对路径查找-->
    <mapper url="file://c:/CarMapper.xml"/>
    <!--查找映射接口同级目录下的Mapper.xml文件-->
    <!--resources中建包需要这样建com/powernode/mybatis/mapper-->
    <!--必须和CarMapper接口放在同级目录下-->
    <!--XML文件的名字必须和接口一致-->
    <mapper class="com.powernode.mybatis.mapper.CarMapper"/>
    
    <!--最常用:路径下自动查找接口对应名字xml文件-->
    <!--前提是:XML文件必须和接口放在同级目录。并且名字一致。-->
    <package name="com.powernode.mybatis.mapper"/>

</mappers>

7 插入数据时获取自动生成的主键

前提:主键是自动生成的。

<!--
		useGeneratedKeys="true" 使用自动生成的主键值。
		keyProperty="id" 指定主键值赋值给对象的哪个属性。这个就表示将主键值赋值给Car对象的id属性。
-->
<insert id="insertCarUseGeneratedKeys" useGeneratedKeys="true" keyProperty="id">
    insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>

把自动递增的主键返回给了id

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值