MyBatis(九)MyBatis小技巧

一、#{}和${}

#{}:先编译sql语句,再给占位符传值,底层是PreparedStatement实现。可以防止sql注入,比较常用。

${}:先进行sql语句拼接,然后再编译sql语句,底层是Statement实现。存在sql注入现象。只有在需要进行sql语句关键字拼接的情况下才会用到。

需求:根据car_type查询汽车

模块名:mybatis-005-antic

1、使用#{}

第1步、创建新模块:

MyBatis(九)MyBatis小技巧_第1张图片

第2步、pom.xml文件引入依赖(mybatis依赖、mysql依赖、junit依赖、logback依赖)



    4.0.0

    com.powernode
    mybatis-006-antic
    1.0-SNAPSHOT
    jar


    
        
        
            org.mybatis
            mybatis
            3.5.10
        
        
        
            mysql
            mysql-connector-java
            8.0.30
        
        
        
            junit
            junit
            4.13.2
            test
        
        
        
            ch.qos.logback
            logback-classic
            1.2.11
        
    

    
        17
        17
        UTF-8

    

第3步、根目录(resources)下创建(CarMapper.xml、jdbc.properties、logback.xml、mybatis-config.xml)

MyBatis(九)MyBatis小技巧_第2张图片

 ①、CarMapper.xml





    

②、jdbc.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:1997/powernode
jdbc.username=root
jdbc.password=123456

③、logback.xml




    
    
        
            
            %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n
        
    

    
    
    
    
    

    
    
        
        
    

④、mybatis-config.xml





    

    
        
            
            
                
                
                
                
            
        
    
    
        
        
    

第4步、编写接口、pojo类、工具类

MyBatis(九)MyBatis小技巧_第3张图片

①、Carmapper

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;

import java.util.List;

/**
 * @author wuw
 * @since 2023-04-07 11:04:43
 */
public interface CarMapper {
    /**
     * 根据car_num获取Car
     * @param carType
     * @return
     */
    List selectByCarType(String carType);
}

②、Car

package com.powernode.mybatis.pojo;

/**
 * @author wuw
 * @since 2023-04-07 11:53:16
 */
public class Car {
    private Long id;
    private String carNum;
    private String brand;
    private Double guidePrice;
    private String produceTime;
    private String carType;
    // 构造方法
    // set get方法
    // toString方法
}

③、SqlSessionUtil

package com.powernode.mybatis.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * @author wuw
 * @since 2023-04-04 09:42:28
 */
public class SqlSessionUtil {
    private static SqlSessionFactory sqlSessionFactory;

    /**
     * 类加载时初始化sqlSessionFactory对象
     */
    static {
        try {
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static ThreadLocal local = new ThreadLocal<>();

    /**
     * 每调用一次openSession()可获取一个新的会话,该会话支持自动提交。
     *
     * @return 新的会话对象
     */
    public static SqlSession openSession() {
        SqlSession sqlSession = local.get();
        if (sqlSession == null) {
            sqlSession = sqlSessionFactory.openSession();
            local.set(sqlSession);
        }
        return sqlSession;
    }

    /**
     * 关闭SqlSession对象
     * @param sqlSession
     */
    public static void close(SqlSession sqlSession){
        if (sqlSession != null) {
            sqlSession.close();
        }
        local.remove();
    }
}

第5步、编写测试类

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.junit.Test;

import java.util.List;

/**
 * @author wuw
 * @since 2023-04-07 11:54:23
 */
public class CarMapperTest {

    @Test
    public void testSelectByCarType(){
        CarMapper mapper = (CarMapper) SqlSessionUtil.openSession().getMapper(CarMapper.class);
        List cars = mapper.selectByCarType("燃油车");
        cars.forEach(car -> System.out.println(car));
    }
}

第6步、运行

MyBatis(九)MyBatis小技巧_第4张图片

通过执行可以清楚的看到,sql语句中是带有 ? 的,这个 ? 就是大家在JDBC中所学的占位符,专门用来接收值的。

把“燃油车”以String类型的值,传递给 ?

这就是 #{},它会先进行sql语句的预编译,然后再给占位符传值

 2、使用${}

同样的需求,我们使用${}来完成

CarMapper.xml文件修改如下:





    

再次运行测试程序:

出现以上错误,因为${} 是先进行sql语句的拼接,然后再编译,出现语法错误是正常的,因为燃油车是一个字符串,所以在sql语句中应该添加单引号。

修改一下:





    

再次运行程序:

MyBatis(九)MyBatis小技巧_第5张图片

通过以上测试,可以看出,对于以上这种需求来说,还是建议使用 #{} 的方式。

原则:能用 #{} 就不用 ${}

 3、什么情况下必须使用${}

当需要进行sql语句关键字拼接的时候。必须使用${}

需求:通过向sql语句中注入asc或desc关键字,来完成数据的升序或降序排列。

  • 先使用#{}尝试:

第一步、CarMapper接口:

/**
 * 查询所有的Car
 * @param ascOrDesc asc或desc
 * @return
 */
List selectAll(String ascOrDesc);

第二步、CarMapper.xml文件:

第三步、测试程序:

@Test
    public void testSelectAll(){
        CarMapper mapper = (CarMapper) SqlSessionUtil.openSession().getMapper(CarMapper.class);
        List cars = mapper.selectAll("desc");
        cars.forEach(car -> System.out.println(car));
    }

报以下错误:

MyBatis(九)MyBatis小技巧_第6张图片

报错的原因是sql语句不合法,因为采用这种方式传值,最终sql语句会是这样:

select id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType from t_car order by carNum 'desc'

desc是一个关键字,不能带单引号的,所以在进行sql语句关键字拼接的时候,必须使用${}

 第4步、使用${} 改造、修改CarMapper.xml

第5步、再次执行测试程序

MyBatis(九)MyBatis小技巧_第7张图片

 4、拼接表名

业务背景:实际开发中,有的表数据量非常庞大,可能会采用分表方式进行存储,比如每天生成一张表,表的名字与日期挂钩,例如:2022年8月1日生成的表:t_user20220108。2000年1月1日生成的表:t_user20000101。此时前端在进行查询的时候会提交一个具体的日期,比如前端提交的日期为:2000年1月1日,那么后端就会根据这个日期动态拼接表名为:t_user20000101。有了这个表名之后,将表名拼接到sql语句当中,返回查询结果。那么大家思考一下,拼接表名到sql语句当中应该使用#{} 还是 ${} 呢?

  • 使用#{}会是这样:select * from 't_car'
  • 使用${}会是这样:select * from t_car

CarMapper.xml:

CarMapper接口:

/**
 * 根据表名查询所有的Car
 * @param tableName
 * @return
 */
List selectAllByTableName(String tableName);

CarMapperTest.testSelectAllByTableName:

@Test
public void testSelectAllByTableName(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List cars = mapper.selectAllByTableName("t_car");
    cars.forEach(car -> System.out.println(car));
}

执行结果:

MyBatis(九)MyBatis小技巧_第8张图片

 5、批量删除

业务背景:一次删除多条记录。

如果使用mybatis处理,应该使用#{} 还是 ${}

使用#{} :delete from t_user where id in('1,2,3') 执行错误:1292 - Truncated incorrect DOUBLE value: '1,2,3'

使用${} :delete from t_user where id in(1, 2, 3)

第1步、接口CarMapper接口:

    /**
     * 根据id批量删除
     * @param ids
     * @return
     */
    int deleteBatch(String ids);
}

第2步、CarMapper.xml


  delete from t_car where id in(${ids})

第3步、测试类

@Test
public void testDeleteBatch(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    int count = mapper.deleteBatch("1,2");
    System.out.println("删除了几条记录:" + count);
    SqlSessionUtil.openSession().commit();
}

第4步、运行,update了两条数据

MyBatis(九)MyBatis小技巧_第9张图片

 6、模糊查询

需求:查询比亚迪系列的汽车。【只要品牌brand中含有比亚迪两个字的都查询出来。】

①、使用${}

第1步、CarMapper接口

/**
     * 根据品牌进行模糊查询
     * @param likeBrank
     * @return
     */
List selectLikeByBrand(String likeBrank);

第2步、CarMapper.xml

第3步、编写测试类

@Test
public void testSelectLikeByBrand(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List cars = mapper.selectLikeByBrand("比亚迪");
    cars.forEach(car -> System.out.println(car));
}

第4步:运行

MyBatis(九)MyBatis小技巧_第10张图片 二、typeAliases

首先观察一下CarMapper.xml中的配置信息:






    

    

resultType属性用来指定查询结果集的封装类型,这个名字太长,可以起别名吗?可以。

在mybatis-config.xml文件中使用typeAliases标签来起别名,包括两种方式:

第一种方式:typeAlias

mybatis-config.xml文件:


  

首先要注意typeAliases标签的放置位置,如果不清楚的话,可以看看错误提示信息。

typeAliases标签中的typeAlias可以写多个。

typeAlias:

        type属性:指定给哪个类起别名

        alias属性:别名。

        alias属性不是必须的,如果缺省的话,type属性指定的类型名的简类名作为别名。

        alias是大小写不敏感的。也就是说假设alias="Car",再用的时候,可以是CAR,也可以是car,也可以是Car,都行。

第二种方式:package

如果一个包下的类太多,每个类都要起别名,会导致typeAlias标签配置较多,所以mybatis用提供package的配置方式,只需要指定包名,该包下的所有类都自动起别名,别名就是简类名。并且别名不区分大小写。

mybatis-config.xml文件:


  

测试:

在mybatis-config中配置

MyBatis(九)MyBatis小技巧_第11张图片

 CarMapper中映射一下

MyBatis(九)MyBatis小技巧_第12张图片

 运行测试代码

MyBatis(九)MyBatis小技巧_第13张图片

三、mappers

SQL映射文件的配置方式包括四种:

  • resource:从类路径中加载
  • url:从指定的全限定资源路径中加载
  • class:使用映射器接口实现类的完全限定类名
  • package:将包内的映射器接口实现全部注册为映射器

1、resource

这种方式是从类路径中加载配置文件,所以这种方式要求SQL映射文件必须放在resources目录下或其子目录下。


  
  
  

2、url

这种方式显然使用了绝对路径的方式,这种配置对SQL映射文件存放的位置没有要求,随意。


  
  
  

3、class(使用的少,移植性太差)

如果使用这种方式必须满足以下条件:

  • SQL映射文件和mapper接口放在同一个目录下。
  • SQL映射文件的名字也必须和mapper接口名一致。


  
  

将CarMapper.xml文件移动到和mapper接口同一个目录下:

  • 在resources目录下新建:com/powernode/mybatis/mapper【这里千万要注意:不能这样新建 com.powernode.mybatis.dao
  • 将CarMapper.xml文件移动到mapper目录下
  • 修改mybatis-config.xml文件

4、package

如果class较多,可以使用这种package的方式,但前提条件和上一种方式一样。



  

四、idea配置文件模板

mybatis-config.xml和SqlMapper.xml文件可以在IDEA中提前创建好模板,以后通过模板创建配置文件。

MyBatis(九)MyBatis小技巧_第14张图片

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

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

业务背景:一个用户有多个角色。

MyBatis(九)MyBatis小技巧_第15张图片

插入一条新的记录之后,自动生成了主键,而这个主键需要在其他表中使用时。

插入一个用户数据的同时需要给该用户分配角色:需要将生成的用户的id插入到角色表的user_id字段上。

第一种方式:可以先插入用户数据,再写一条查询语句获取id,然后再插入user_id字段。【比较麻烦】

第二种方式:mybatis提供了一种方式更加便捷。

 第1步:CarMapper

/**
     * 获取自动生成的主键
     * @param car
     */
void insertUseGeneratedKeys(Car car);

第2步:CarMapper.xml


  insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})

第3步:CarMapperTest测试

@Test
    public void testInsertUseGeneratedKeys(){
        CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
        Car car = new Car();
        car.setCarNum("5262");
        car.setBrand("BYD汉");
        car.setGuidePrice(30.3);
        car.setProduceTime("2020-10-11");
        car.setCarType("新能源");
        mapper.insertUseGeneratedKeys(car);
        SqlSessionUtil.openSession().commit();
        System.out.println("获取的id为:"+" "+car.getId());
    }

第4步:运行

MyBatis(九)MyBatis小技巧_第16张图片

你可能感兴趣的:(mybatis,intellij-idea,java)