MyBatis参数处理和查询结果映射如何实现映射?

摘要:实际开发中应用细节 #{}和${}的区别? ‘#{}’:先编译sql语句,再给占位符传值,底层是PreparedStatement实现,可以防止sql注入,比较常用。 ‘#{}’传来的字符串类型的数据会自带单引号,比如:user_name=
实际开发中应用细节 #{}和${}的区别? ‘#{}’:先编译sql语句,再给占位符传值,底层是PreparedStatement实现,可以防止sql注入,比较常用。 ‘#{}’传来的字符串类型的数据会自带单引号,比如:user_name=#{name} 会编译为 user_name=‘张三’ ${}:先进行sql语句拼接,再编译sql语句,底层是Statement实现。存在sql注入现象。只有在需要进行sql关键字拼接的情况下才会用到。 ${}传来的字符串类型的数据不带单引号,比如:user_name=#{name} 会编译为 user_name=张三 。这样会报语法错误。 优先使用#{} 那么什么时候使用${}呢? 在使用sql拼接的时候会用到,比如一个数据的查询结果是升序还是降序有前端传来的参数决定。因此使用${}更合适: order by age=${orderType} 会编译为 order by age=asc。 如果使用#{}处理的话会编译为order by age=‘asc’ 会报语法错误! 当拼接表名时也会用到。 一些数据会分表存储。比如日志表,因为日志数据会非常大,可以每天生成一个日志表,每张表以当天的日期作为名称,例如: log_2022-02-11、log_2022-02-12、log_2022-02-13. 这样查某一天的日志时,可以将log_和日期进行拼接 然后查询,此时就要用到${} 批量删除 批量删除时,参数一般为字符串,比如传来的参数id值为:‘1,2,3,4’。直接用where id in (#{id})会失效。 这里应该使用$() 。sql会编译为where id in (1,2,3,4) 结果执行成功。 模糊查询 方案一:使用sql语句拼接 where name like '%${name}%' 方案二:使用concat函数 where name like concat('%',#{name},'%') 此时会编译为 where name like concat('%','涨三','%') 执行成功。 方案三:where name like "%"#{name}"%" 别名机制 当XxxMapper.xml中resultType的值太长,也就是返回值的全限定类名太长,可以使用别名机制。 先在mybatis-config.xml中配置如下: <!-- 起别名,typeAliases标签要放在properties、settings 标签后面--> <typeAliases> <!-- type:指定给哪个类型起别名 alias:指定别名。别名不区分大小写 然后在CarMapper.xml文件中就可以直接使用别名car来代替全类名com.ali.pojo.Car了 --> <typeAlias type="com.ali.pojo.Car" alias="car"/> </typeAliases> 这里的alias属性其实可以省略。当alias省略时,别名就是类的简名,比如: <typeAlias type="com.ali.pojo.Car"/> 的别名就是car、CAR等,不区分大小写。 ​ 还有更加方便的一种方式,可以指定包名,mybatis会自动给这个包下的所i有类起别名,别名就是类名: <typeAliases> <package name="com.ali.pojo"/> </typeAliases> 在CarMapper.xml中就可以使用别名了 <select id="selectCarById" resultType="car"> SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType FROM t_car WHERE id = #{id} </select> 注意:这里的别名不区分大小写。即使写成resultType="Car" 也会执行成功! mapper的配置 <mappers> <!-- 执行xxxMapper.xml文件中的SQL语句--> <!-- resource属性自动从类的路径下加载xxxMapper.xml文件 url属性直接从文件系统绝对路径加载xxxMapper.xml文件,不推荐,移植性太差。 class属性指定一个全限定接口名,mybaits会去这个接口的同级目录下查找对应Mapepr.xml文件 比如以下配置,Mybatis会去com.ali.mapper包下查找CarMapper.xml文件。 --> <mapper class="com.ali.mapper.CarMapper"/> <mapper resource="CarMapper.xml"/> <!--package:表示从指定的包下查找所有的xxxMapper.xml文件,并且自动加载它们。 前提必须把xml文件和接口放在统计目录下。并且名字一致。 实际开发中 使用这种方式--> <package name="com.ali.mapper"/> </mappers> 插入数据时获取自动生成的主键 <!-- useGeneratedKeys="true" 表示使用JDBC的getGeneratedKeys方法获取数据库自动生成的主键值, keyProperty="id"表示将获取到的主键值封装到Car对象的id属性中。--> <insert id="insertCarGetId" useGeneratedKeys="true" keyProperty="id"> INSERT INTO t_car (id, car_num, brand,guide_price,produce_time,car_type) VALUES (null, #{carNum}, #{brand},#{guidePrice},#{produceTime},#{carType}) </insert> 这样设置后,在新增时传入的car对象在sql执行完后,主键的值可以从car.getId()方法中获得。 MyBatis参数处理 简单类型参数 byte、int、short、long、char、float、double、String、Date,及其对应的包装类都适用简单类型参数。 下面以Long类型为例: <!-- 对应的接口方法: Car selectCarById(Long id); parameterType属性:指定传入参数的类型。在这个例子中,传入参数是一个Long类型的id。 mybatis框架自带类型推断机制,所以大部分情况下parameterType属性可以省略不写, --> <select id="selectCarById" resultType="car" parameterType="java.lang.Long"> SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType FROM t_car WHERE id = #{id} </select> Map参数 <!-- 对应的接口方法: int insertCar(Map<String,Object> map); 参数类型时map集合。 --> <insert id="insertCar" parameterType="map"> INSERT INTO t_car (id, car_num, brand,guide_price,produce_time,car_type) VALUES (null, #{carNum}, #{brand},#{guidePrice},#{produceTime},#{carType}) </insert> 实体类参数 <!--对应的接口方法: int insertCarByPojo(Car car); 参数类型是Pojo类。--> <insert id="insertCarByPojo" > INSERT INTO t_car (id, car_num, brand,guide_price,produce_time,car_type) VALUES (null, #{carNum}, #{brand},#{guidePrice},#{produceTime},#{carType}) </insert> 多参数 <!--对应的接口方法: List<Car> selectCarByNameAndCarType(String name,String carType); 这种多参数的情况,mybatis框架会将多个参数封装成一个map集合,并且map会这样设置: map.put("arg0",第一个参数值); map.put("arg1",第二个参数值); map.put("param1",第一个参数值); map.put("param2",第二个参数值); 所以#{arg0} 和#{param1}都可以获取到第一个参数值,#{arg1}和#{param2}都可以获取到第二个参数值。 --> <select id="selectCarByNameAndCarType" resultType="car" parameterType="java.lang.Long"> SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType FROM t_car WHERE brand = #{arg0} and car_type = #{arg1} </select> @Param注解 <!--对应的接口方法: List<Car> selectCarByNameAndCarType2(@Param("name") String name,@Param("carType") String carType); @Param注解会将底层封装的map中arg0、arg1替换成我们指定的key值name和carType。 param1、param2不会被替换,可以继续使用 --> <select id="selectCarByNameAndCarType2" resultType="car" parameterType="java.lang.Long"> SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType FROM t_car WHERE brand = #{name} and car_type = #{carType} </select> MyBatis查询语句 当sql返回多条记录时,不能使用单个pojo对象接收,不然会报错。 单条查询时,用List接收是没有任何问题的。 返回Map 当返回的数据,没有合适的实体类对应的话,可以采用Map接收。key是字段名,value是字段值。 当返回多条数据时,使用List 接收。 <!-- 对应的接口方法: Map<String,Object> selectCarByIdRetMap(Long id); resultType="map"表示将查询结果封装成一个map集合,map的key是列名,value是列值。 如果需要查询多条记录并封装成map集合,可以使用resultType="list"来封装成一个list集合,list集合中的每个元素都是一个map集合。 --> <select id="selectCarByIdRetMap" resultType="map" > SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType FROM t_car WHERE id = #{id} </select> 返回Map<String,Map> 以每条记录的主键作为key,一条记录作为value <!-- 接口对应的方法: @MapKey("id") // 这个注解表示map的key是id列的值,value是整个记录封装成的map集合。 List<Map<Long,Map<String,Object>> selectAllCarRetMap(); --> <select id="selectAllCarRetMap" resultType="map"> SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType FROM t_car </select> resultMap结果映射 查询结果的列名和Java对象的属性名对应不上怎么办? 方案一:as 起别名 方案二:使用resultMap进行结果映射 方案三:开启驼峰命名自动映射 <!--定义一个结果映射,在结果映射中,指定数据库表的字段和Java对象的属性之间的映射关系。 id属性是结果映射的唯一标识,将来要用在select标签中;type属性是结果映射对应的Java类型。--> <resultMap id="carResultMap" type="Car"> <!--建议配上主键,因为主键在结果映射中有特殊的意义, 主键会被mybatis框架缓存起来,如果查询结果中有重复的主键值,mybatis框架会将它们封装成同一个Java对象。--> <id property="id" column="id"></id> <!--property指定Java对象的属性,column指定数据库表的字段。 当数据库表的字段名和Java对象的属性名一致时,可以不配置--> <result property="carNum" column="car_num"></result> <result property="guidePrice" column="guide_price"></result> <result property="produceTime" column="produce_time"></result> <result property="carType" column="car_type"></result> </resultMap> <!--resultMap表示指定使用哪个结果映射,resultMap的值时resultMap标签的id--> <select id="selectAllCarResultMap" resultMap="carResultMap"> SELECT * FROM t_car </select> 开启驼峰命名自动映射 前提时Java的属性名和数据库表的字段名必须符合命名规范。 可以将car_type对应为carType 在mybatis-config.xml文件中进行如下配置即可开启该功能,默认值是false: <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> 返回总记录条数 <!-- 对应的接口方法: long selectTotalCount(); --> <select id="selectTotalCount" resultType="long"> SELECT count(*) FROM t_car </select>