准备环境
1、数据库表tb_brand
2、实体类Brand
3、测试用例
3、1在test包中的java包中创建测试类com.xyy.test.MybatisTest.java
4、安装MyBatisX插件
添加插件后,因为在Mapper代理开发时,Mapper接口要和Mapper.xml映射文件放在同一个报下,在如下界面中,可以看到接口名前面和每个接口方法名前都会有一个图标,点击便可以跳转到对应的sql映射文件中,点击接口前的图标会跳转到Mapper.xml中的< select >, < delete >, < insert >, < modify >等标签,点击方法对应的图标,便会跳转到Mapper.xml标签里面的sql语句。同样在接口和映射文件中可以互相进行跳转。
如果在接口中加入方法,但是在映射文件中并没有定义一个statement(< select > 等标签),会爆红提示,通过快捷键alt + shift + enter让mybatis帮忙进行创建
增删改查
1、查询
1、1 查询所有数据
从 XML 中构建 SqlSessionFactory
String resource = "mybatis-config.xml"; InputStream resourceAsStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
从 SqlSessionFactory 中获取 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
利用Mapper代理开发来执行sql
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); List<Brand> brands = brandMapper.selectAll(); for(Brand brand : brands) { System.out.println(brand); //这里执行的是查询tb_brand表的所有信息 }
结果如下,但是有个Problem:
为什么会出现这种情况?
这是因为在数据库建表的时候,tb_brand表中column字段名和在java的pojo包下创建的实体类Brand的property属性差异造成的!
在数据库表中字段column定义如上图,再看在java中对应的实体类的属性property
可以看到,这两个映射不匹配,所以才会造成上述原因,在传表中数据给实体类中时,找不到匹配属性,所以会显示为null
解决方案(有多种,这里介绍常用灵活的resultMap)
在对tb_brand表的sql映射文件中加入resultMap,格式如下:
<mapper namespace="com.xyy.mapper.BrandMapper"> <resultMap id = "brandMap" type="Brand"> <result column="brand_name" property="brandName"></result> <result column="company_name" property="companyName"></result> <!--因为只有两个property和tb_brand中的column不对应,所以只写了两个,这里对于映射有两个写法,一个是result标签,就是上面这个,这种是针对于非主键的,对于主键的映射需要通过id,因为实体类中的id属性和表中的id字段对应了,就没必要写,但是也可以写出来,如下图--> </resultMap> <!-- selectAll方法,查询所有品牌信息 --> <select id="selectAll" resultMap="brandMap"> select * from tb_brand; </select> <!-- selectById方法,查询品牌信息,参数为id --> <select id="selectById" resultMap="brandMap"> select * from tb_brand where id = #{id}; </select> </mapper>
添加了resultMap标签,里面有id和type,id是该resultMap标签的唯一标识,type则是需要字段和属性映射的实体类
其次,再将select标签中的resultType删掉,换成resultMap=“其唯一标识”。
官方文档中给出resultType和resultMap不能同时出现
再次运行,结果如下:
对于这些标签的属性,mybatis – MyBatis 3 | XML 映射器 (p2hp.com)给出了非常详细的介绍,可以参阅。
1、2 查看详情
查询所有是将表中所有记录都给查询出来,而查询详情则是将某一条记录拿出来,将所有column字段展示。
步骤流程
1、编写接口方法:Mapper接口
1、1 参数:id
1、2 结果: Brand2、编写SQL语句:SQL映射文件
3、执行方法,测试
<select id="selectById" resultMap="brandMap"> select * from tb_brand where id = #{id}; </select>
参数占位符
1、#{ } :会将其替换成?,为了防止SQL注入
2、${ }:直接拼sql,会存在SQL注入问题
3、使用时机:
3、1 参数传递的时候:#{ }
3、2表名或者列名不固定的情况下:${ } < 动态sql >
参数类型:parameterType:可以省略
特殊字符处理:
sql语句是写在xml文件中的,当sql条件中包含’ > ’ 时便会报错,因为这个是xml中标签的打头,为了避免这种情况:
1、可以使用转移字符,例如对于<的转义字符是:<
2、<![CDATA[ 特殊字符就写在这里面 ]]> 这样,特殊字符就会被当做普通文本来进行处理。(idea通过敲CD回车即可打出快捷键) <![CDATA[...]]>
1、
/** * @param id * @return com.xyy.pojo.Brand * @description 根据id查询品牌信息 */ Brand selectById(int id);
以下是采用#{}的传参方式
以下是采用${}的传参方式,可以看到这是采用拼接,会造成安全隐患
1、3 条件查询
1、3、1 多条件查询
给出表中数据,后面三个条件查询都是对这个操作
步骤
1、编写接口方法:Mapper接口
1、1 参数:所有查询条件
1、2 结果: List< Brand>2、编写SQL语句:SQL映射文件
3、执行方法,测试
多条件就代表会传入多个参数,以下提供了三中参数处理的方式。
以下三种传参方式以后都会有应用场景,将一一介绍:
1、散装参数
//假定用户输入的三个数据条件 int status = 1; String companyName = "华为"; String brandName = "华为"; //处理用户输入的三个条件 companyName = "%" + companyName + "%"; brandName = "%" + brandName + "%"; String resource = "mybatis-config.xml"; InputStream resourceAsStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName); for(Brand brand : brands) { System.out.println(brand); }
2、对象参数
//这里是对象参数 Brand brand = new Brand(); brand.setBrandName(brandName); brand.setCompanyName(companyName); brand.setStatus(status); List<Brand> brands = brandMapper.selectByCondition(brand);
3、map对象
//这里是Map参数 Map map = new HashMap(); map.put("status", status); //这里的键的名称"status需要sql映射文件中的参数一致 //值的名称需要和接收的参数一致即可。 //因为这里接收的参数和sql参数命名一致,所以没啥区别 map.put("companyName", companyName); map.put("brandName", brandName); List<Brand> brands = brandMapper.selectByCondition(map);
总结:
1、3、1、1 多条件判断引入动态sql
引入:
上面的多条件查询会存在一些bug,用户不一定会每次都将所有条件都会输入,这样sql参数就可能接收到null值,最终结果就会有问题。
对此,引入动态条件查询(动态sql)
引入 < if test = “条件表达式” > sql片段 < /if >
<!-- 多条件查询 --> <select id="selectByCondition" resultMap="brandMap"> select * from tb_brand where <if test="status != null"> status = #{status} </if> <if test="brandName != null and brandName != '' "> and brand_name like #{brandName} </if> <if test="companyName != null and companyName != '' "> and company_name like #{companyName}; </if> </select>
1、3、1中的多条件查询可以修改成这样,当用户某个条件没输入字符或者输入为’'时就不会拼接该条件
例如:
在这里可以看到用多个if条件写法可以解决用户部分条件不输入的查询
但是,这个写法会有一些bug,看上面xml代码中,从第二个if标签开始,里面的sql字段都是and开头的,如果第一个if标签没有拼接,则会造成sql语法错误,如下:
解决方案如下:
1、恒等式 1 == 1 (在每个if标签中的条件都加上 and, 同时在where后加上 1 == 1,后面所有的if标签都一视同仁,都是在 1==1 后面进行一个拼接)
2、Mybatis当然想到了这中情况,所以提供了新的标签< where >, 用< where > 抱歉提到原sql中where,这样就不用担心and问题了,
<select id="selectByCondition" resultMap="brandMap"> select * from tb_brand <where> <if test="status != null"> and status = #{status} </if> <if test="brandName != null and brandName != '' "> and brand_name like #{brandName} </if> <if test="companyName != null and companyName != '' "> and company_name like #{companyName}; </if> </where> </select>
这里需要注意一点,用< where > 代替了where后,每个if标签中的sql语句除第一个可以不用加and,后面的都需要加上and,< where > 识别去除and的功能,没有添加and的功能,不然会造成sql语法错误
总结:
1、3、2 单条件查询
针对于如下业务场景,引入但条件查询,就不能像之前多条件查询,一次可以输入多个条件。这种情况下,一次只能输入一个固定的条件,对该条件进行查询。(类似于switch结构,只执行满足条件的case,这里case可以类比于选择的条件)
引入choose(when, otherwise)
<!-- 单条件查询 --> <select id="selectByConditionSingle" resultMap="brandMap"> select * from tb_brand where <choose> <when test="status != null"> status = #{status} </when> <when test="brandName != null and brandName != '' "> brand_name like #{brandName} </when> <when test="companyName != null and companyName != '' "> company_name like #{companyName} </when> <otherwise> 1 = 1 </otherwise> </choose> </select>
这个otherwise可以用之前的< where > 代替where来识别条件个数,如果没有条件拼接,Mybatis就会去掉where,如下:
[后续将慢慢完善]