上文中说道SqlSession执行语句时的用法,不过现在有了一种更简洁的方式 ——使用正确描述每个语句的参数和返回值的接口(比如 UserMapper.class),你现在不仅可以执行更清晰和类型安全的代码,而且还不用担心易错的字符串字面值以及强制类型转换。
文件层次如图:
代码示例:
@AllArgsConstructor @NoArgsConstructor @Getter@Setter @ToString @Alias("User") public class User { private Integer id; private String username; private String password; private Date date; private BigDecimal salary; }
public interface IUserService { void save(User user); void delete(Integer id); void update(User user); User find(Integer id,String username); List<User> findAll(); List<User> findOrderByColumn(String column); void deleteSelectAll(int[] ids); }
public class UserServiceImpl implements IUserService { @Override public void save(User user) { SqlSession session = MybatisUtil.getSession(); /*MAP接口的代处理对象*/ UserMapper um = session.getMapper(UserMapper.class); um.save(user); session.commit(); session.close(); } @Override public void delete(Integer id) { SqlSession session = MybatisUtil.getSession(); /*MAP接口的代处理对象*/ UserMapper um = session.getMapper(UserMapper.class); um.delete(id); session.commit(); session.close(); } @Override public void update(User user) { SqlSession session = MybatisUtil.getSession(); /*MAP接口的代处理对象*/ UserMapper um = session.getMapper(UserMapper.class); um.update(user); session.commit(); session.close(); } @Override public User find(Integer id,String username) { SqlSession session = MybatisUtil.getSession(); /*MAP接口的代处理对象*/ UserMapper um = session.getMapper(UserMapper.class); User user = um.find(id, username); session.close(); return user; } @Override public List<User> findAll() { SqlSession session = MybatisUtil.getSession(); /*MAP接口的代处理对象*/ UserMapper um = session.getMapper(UserMapper.class); List<User> all = um.findAll(); session.close(); return all; } @Override public List<User> findOrderByColumn(String column) { SqlSession session = MybatisUtil.getSession(); /*MAP接口的代处理对象*/ UserMapper um = session.getMapper(UserMapper.class); List<User> orderByColumn = um.findOrderByColumn(column); session.close(); return orderByColumn; } @Override public void deleteSelectAll(int[] ids) { SqlSession session = MybatisUtil.getSession(); /*MAP接口的代处理对象*/ UserMapper um = session.getMapper(UserMapper.class); um.deleteSelectAll(ids); session.commit(); session.close(); } }
public interface UserMapper { void save(User user); void delete(Integer id); void update(User user); User find(@Param("id") Integer id,@Param("username") String username); List<User> findOrderByColumn(@Param("column") String column); List<User> findAll(); void deleteSelectAll(int[] ids); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace:写UserMapper接口的全限定名--> <mapper namespace="com.test.mapper.UserMapper"> <!-- #{}表示调用对象中响应的get方法--> <!-- 注意,这里的标签中的id值是唯一的 因为在UserMapper的底层是将namespace和id一起作为一个Map集合的key,sql语句作为value,因为map的key唯一,所以id必须唯一 --> <!-- 保存 --> <!--useGeneratedKeys为true表示返回主键的值 keyProperty表示返回给对象的哪个属性--> <insert id="save" useGeneratedKeys="true" keyProperty="id"> insert into user values(null,#{username},#{password},#{date},#{salary}) </insert> <!-- 删除 --> <delete id="delete"> delete from user where id=#{id} </delete> <!--批量删除--> <delete id="deleteSelectAll"> delete from user where id in <foreach collection="array" open="(" close=")" item="item" separator=","> #{item} </foreach> </delete> <!-- 更新 --> <update id="update"> update user <trim prefix="set" suffixOverrides=","> <if test="username!=null"> username=#{username}, </if> <if test="password!=null"> password=#{password}, </if> <if test="date!=null"> date=#{date}, </if> <if test="salary!=null"> salary=#{salary}, </if> </trim> where id=#{id} </update> <!--type:把结果集封装成对象的类型--> <resultMap id="myResultMap" type="User"> <id column="id" property="id"/> <result column="username" property="username"/> <result column="password" property="password"/> <result column="date" property="date"/> <result column="salary" property="salary"/> </resultMap> <!-- 查询一个 --> <!--<select id="find" resultMap="myResultMap"> select * from user where 1=1 <if test="username !=null"> and username = #{username} </if> <if test="id != null"> and id = #{id} </if> </select>--> <select id="find" resultMap="myResultMap"> select * from user <where> <if test="username !=null"> username = #{username} </if> <if test="id != null"> and id = #{id} </if> </where> </select> <!-- 查询全部 --> <select id="findAll" resultType="User"> select * from user </select> <!--通过列名降序查询--> <select id="findOrderByColumn" resultType="User"> select * from user order by ${column} desc </select> </mapper>
几个知识点介绍:重点
1、Mapper接口的使用方式及原理
1.mapper映射文件中的namespace的值,必须等于mapper接口的全限定名
2.mapper映射文件中的Sql的id,必须等于mapper接口中的方法名
3.mapper映射文件中的Sql的paramterType必须跟对应的方法的类型相同
4.方法的返回值必须和resultType或者resultMap的值保持一致
以Update为例,图中解释了update的原理
2、保存数据自动获取数据库生成的主键
<!--useGeneratedKeys为true表示返回主键的值 keyProperty表示返回给对象的哪个属性--> <insert id="save" useGeneratedKeys="true" keyProperty="id"> insert into user values(null,#{username},#{password},#{date},#{salary}) </insert>
3、resultMap的使用与where的作用 以及if的作用
<!--resultMap:结果集映射标签 type:把结果集封装成对象的类型 id:当前结果集映射的唯一标识 在列名与属性名不一致时使用这两个标签进行转换 column:数据库中的列名 property:类中的属性名 --> <resultMap id="myResultMap" type="User"> <id column="id" property="id"/> <result column="username" property="username"/> <result column="password" property="password"/> <result column="date" property="date"/> <result column="salary" property="salary"/> </resultMap> <!-- 查询 --> <!-- where标签
自动拼接里面的sql语句,当where里面没有成立的条件时,则什么都没有
如果里面有条件成立,则自动为语句前加上where ,若语句为and开头,则自动删除and
if标签
if test="判断条件" 如果条件成立,则执行if中间的语句,与jstl用法相同
-->
<select id="find" resultMap="myResultMap"> select * from user <where> <if test="username !=null"> username = #{username} </if> <if test="id != null"> and id = #{id} </if> </where> </select>
4、动态sql
if 上面已经介绍过了
choose 类似与java中的switch
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
where 上面已经介绍过了
set
<update id="update"> update user <trim prefix="set" suffixOverrides=","> <if test="username!=null"> username=#{username}, </if> <if test="password!=null"> password=#{password}, </if> </trim> where id=#{id} </update> <!--set原理与where很相似,set会自动处理语句后的逗号,如果语句以逗号结尾则会删掉逗号,以及会给语句前加上set关键字-->
trim
<!--prefix:前缀,在返回的字符串前添加什么内容 suffix:后缀,在饭后的字符串后添加什么内容 prefixOverrides:当字符串以什么内容开头时,该内容会被覆盖 suffixOverrides:当字符串以什么内容结尾时,该内容会被覆盖 --> <trim prefix="" suffix="" prefixOverrides="" suffixOverrides=""> </trim> <!--trim模仿where--> <trim prefix="where" prefixOverrides="and'></trim> <!--trim模仿set--> <trim prefix="set" suffixOverrides=","></trim>
foreach
<!--collection:遍历元素的类型 item:遍历时每次的变量名 index:每次的下标(从0开始计数) open:字符串开头添加 close:字符串结尾添加 separator:元素之间的分隔符--> <select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> </select>
5、Sql语句中${}和#{}的区别
#{}:会吧参数的位置使用”?”做占位符,执行SQL的时候才会替换”?”的值
${}:直接把参数中的值作为SQL的一部分来执行 -----------> 可能会有SQL注入的问题
如何选用?
${}:当插入的参数时作为SQL执行的一部分的时候必须使用${};
#{}:当传入的参数时同数据库进行交互的时候,使用#{}.
简单的判断:传入的参数在SQL中是否能够加上单引号 可以加单引号,使用#{},不能加单引号,使用${}
6、多参数问题处理
解决方案: 把多个对象封装成一个对象
1、封装成一个javaBean对象
2、封装成一个Map对象 将属性名设为Map的key,属性值设为value
3、使用@param注解