MyBatis
-
概述
-
Mybatis 要优于之前的 JDBC
-
MyBatis快速入门
-
如果SQL语句返回的是集合,比如List<User> ,resultType属性的值只需要写泛型类型就行,也就是 User
-
项目结构 - 接口与 xml文件层级对应
-
-
日志
-
log4j的pom坐标
<!-- log start --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.6</version> </dependency>
-
log4j.properties
##设置日志记录到控制台的方式 log4j.appender.std=org.apache.log4j.ConsoleAppender log4j.appender.std.Target=System.err log4j.appender.std.layout=org.apache.log4j.PatternLayout log4j.appender.std.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n ##设置日志记录到文件的方式 log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.File=mylog.txt log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ##日志输出的级别,以及配置记录方案,级别越低(error>warn>info>debug>trace),打印的信息越多。 ##开发一般写debug,std(控制台显示)。项目上线推荐使用error,file。 log4j.rootLogger= info,std,file
-
-
Mapper接口使用规范
-
核心配置文件SqlMapConfig.xml详解
- 文件结构
-
properties(引入配置文件)
-
typeAliases(类型别名)
- typeAliases起别名,如果用package,会给一个文件夹起别名,但是你用里面的实体类时,返回值参数你就要用全小写
-
environments(环境配置)
-
mappers
· mappers:配置关联映射文件 - 要么提供xml文件路径( ‘/’ 分隔),要么提供接口的路径( ‘.’ 分隔)
按照mapper.xml路径配置 使用/分割路径
按照接口文件路径配置 使用.分割路径
批量配置 使用.分割路径,只需要配置包名。不需要设置具体的接口名。
MyBatis 练习
-
配置文件完成增删改查
-
查询 - 查询所有商品
~ 注意事项
-
查询 - 查看商品详情
-
查询 - 模糊查询
~ ${value} 和 #{value}的区别
-
-
查询 - 多条件查询
- @Param主要是用来注解dao类中方法的参数,便于在对应的dao.xml文件中引用。
-
添加 - 添加商品信息
~ 增删改需要提交事务才会真的生效,或者当初创建开会话的时候设置自动提交
-
添加 - 添加订单信息 (主键自增回填 - 拿到自增后的 id,有的时候要用)
-
~ order属性的值AFTER :用于等算法生成独特 id 再新增数据的情况。
-
修改 - 修改商品所有信息
-
删除 - 删除指定商品
-
使用注解的测试类 - 测试方法
public class MyBatisTest { //工厂对象 private static SqlSessionFactory factory; //会话对象 private SqlSession sqlSession; //代理对象 private BrandDao brandDao; //快捷键:快速转成全局变量 Ctrl+Alt+F @BeforeClass public static void getSqlFactory() throws Exception { //获取核心文件输入流 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); //获取工厂创建对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //获取工厂对象 factory = builder.build(in); } @Before public void getSqlSession() { //获取会话对象 //是否开启事务,由具体业务需求决定的。 //openSession() 默认开启事务管理 sqlSession = factory.openSession(); //openSession(boolean var1 ) 设置自动提交事务,var1值设置为true之后,增删改操作会自动提交事务 //sqlSession = factory.openSession(true); //获取代理对象 brandDao = sqlSession.getMapper(BrandDao.class); } @Test public void testSelectAll() throws Exception { //执行sql操作 List<Brand> brands = brandDao.selectAll(); //处理结果 for (Brand brand : brands) { System.out.println(brand); } } @Test public void testSelectById() throws Exception { //执行sql操作 int id = 1; Brand brand = brandDao.selectById(id); //处理结果 System.out.println(brand); } @Test public void testSelectByBrandName() throws Exception { //执行sql操作 String brandName = "华为"; List<Brand> brands = brandDao.selectByBrandName(brandName); //处理结果 for (Brand brand : brands) { System.out.println(brand); } } @Test public void testSelectByConditions1() throws Exception { //执行sql操作 int status = 1; String conpanyName = "有限公司"; String brandName = "华为"; List<Brand> brands = brandDao.selectByConditions1(status, conpanyName, brandName); //处理结果 for (Brand brand : brands) { System.out.println(brand); } } @Test public void testSelectByConditions2() throws Exception { //执行sql操作 int status = 1; String companyName = "有限公司"; String brandName = "华为"; //List<Brand> brands = brandDao.selectByConditions2(status, conpanyName, brandName); Brand brand = new Brand(); brand.setStatus(status); brand.setCompanyName(companyName); brand.setBrandName(brandName); //List<Brand> brands = brandDao.selectByConditions2(brand); Map brandMap = new HashMap<>(); brandMap.put("status", status); brandMap.put("companyName", companyName); brandMap.put("brandName", brandName); List<Brand> brands = brandDao.selectByConditions2(brandMap); //处理结果 for (Brand brand2 : brands) { System.out.println(brand2); } } @Test public void testInsertBrand() throws Exception { //执行sql操作 Brand brand = new Brand(); brand.setBrandName("华为荣耀"); brand.setCompanyName("华为技术有限公司"); brand.setOrdered(102); brand.setDescription("一家伟大的公司..."); brand.setStatus(1); brandDao.insertBrand(brand); //因为sqlSession默认开启事务管理,如果执行增删改,必须手动提交事务。 sqlSession.commit(); } @Test public void testInsertBrandGetID() throws Exception { //执行sql操作 Brand brand = new Brand(); brand.setBrandName("华为荣耀"); brand.setCompanyName("华为技术有限公司"); brand.setOrdered(102); brand.setDescription("一家伟大的公司..."); brand.setStatus(1); System.out.println("brand.getId:" + brand.getId());//null brandDao.insertBrandGetID(brand); //因为sqlSession默认开启事务管理,如果执行增删改,必须手动提交事务。 sqlSession.commit(); //获取回填数据 System.out.println("brand.getId:" + brand.getId());//xx } @Test public void testUpdateBrand() throws Exception { //执行sql操作 Brand brand = new Brand(); brand.setId(14); brand.setBrandName("华为荣耀666"); brand.setCompanyName("华为666"); brand.setOrdered(105); brand.setDescription("一家特别伟大的公司..."); brand.setStatus(0); brandDao.updateBrand(brand); //因为sqlSession默认开启事务管理,如果执行增删改,必须手动提交事务。 sqlSession.commit(); } @Test public void testDeleteById() throws Exception { //执行sql操作 int id = 14; brandDao.deleteById(id); //因为sqlSession默认开启事务管理,如果执行增删改,必须手动提交事务。 sqlSession.commit(); } @After public void closeSqlSession() { //关闭会话对象 sqlSession.close(); } }
-
BrandDao.java - 定义了增删改查等操作方法
public interface BrandDao { //查看所有产品 List<Brand> selectAll(); //查看商品详情 Brand selectById(int id); //模糊搜索 List<Brand> selectByBrandName(String brandName); //多条件查询 List<Brand> selectByConditions1(int status, String companyName, String brandName); //List<Brand> selectByConditions2(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName); //List<Brand> selectByConditions2(Brand brand); List<Brand> selectByConditions2(Map brandMap); //添加商品 void insertBrand(Brand brand); //添加订单信息(主键自增回填) void insertBrandGetID(Brand brand); //修改商品信息 void updateBrand(Brand brand); //删除商品 void deleteById(int id); }
-
BrandDao.xml - 增删改查方法具体SQL语句的配置语句
<?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"> <mapper namespace="com.itheima.dao.mapper.BrandDao"> <resultMap id="brandResultMap" type="brand"> <result column="brand_name" property="brandName"></result> <result column="company_name" property="companyName"></result> </resultMap> <!--查询所有产品--> <!--解决数据库字段名与实体类属性名不一致问题:方式1--> <!--<select id="selectAll" resultType="brand"> select id, brand_name AS brandName, company_name AS companyName, ordered, description, status from tb_brand; </select>--> <!--解决数据库字段名与实体类属性名不一致问题:方式2 引入结果映射--> <select id="selectAll" resultMap="brandResultMap"> SELECT * FROM tb_brand; </select> <!--查询商品详情--> <!--<select id="selectById" resultMap="brandResultMap" parameterType="int"> select * from tb_brand where id=${id}; </select>--> <select id="selectById" resultMap="brandResultMap" parameterType="int"> SELECT * FROM tb_brand WHERE id = #{id}; </select> <!--模糊搜索--> <!--<select id="selectByBrandName" resultMap="brandResultMap" parameterType="String"> select * from tb_brand WHERE brand_name LIKE '%${brandName}%'; </select>--> <select id="selectByBrandName" resultMap="brandResultMap" parameterType="String"> SELECT * FROM tb_brand WHERE brand_name LIKE CONCAT('%', #{brandName}, '%'); </select> <!--多条件查询--> <select id="selectByConditions1" resultMap="brandResultMap"> SELECT * FROM tb_brand WHERE status = #{arg0} AND company_name LIKE CONCAT('%', #{arg1}, '%') AND brand_name LIKE CONCAT('%', #{arg2}, '%'); </select> <select id="selectByConditions2" resultMap="brandResultMap"> SELECT * FROM tb_brand WHERE status = #{status} AND company_name LIKE CONCAT('%', #{companyName}, '%') AND brand_name LIKE CONCAT('%', #{brandName}, '%'); </select> <!--添加商品--> <insert id="insertBrand"> INSERT INTO tb_brand VALUES (NULL, #{brandName}, #{companyName}, #{ordered}, #{description}, #{status}); </insert> <!--添加订单信息(主键自增回填)--> <!--useGeneratedKeys表示是否自增回填 true表示要自增回填--> <!--keyProperty 对应实体类的中是属性--> <!--<insert id="insertBrandGetID" useGeneratedKeys="true" keyProperty="id">--> <!-- INSERT INTO tb_brand--> <!-- VALUES (NULL, #{brandName}, #{companyName}, #{ordered}, #{description}, #{status});--> <!--</insert>--> <!--resultType:键返回类型--> <!--keyColumn:键对应的是数据库的哪个字段--> <!--keyProperty:对应实体类的中是属性--> <!--order:表示获取insert执行前(BEFORE)还是执行后(AFTER)的键值--> <insert id="insertBrandGetID"> <selectKey resultType="int" keyColumn="id" keyProperty="id" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO tb_brand VALUES (NULL, #{brandName}, #{companyName}, #{ordered}, #{description}, #{status}); </insert> <!--修改商品信息--> <update id="updateBrand"> UPDATE tb_brand SET brand_name = #{brandName}, company_name = #{companyName}, ordered = #{ordered}, description = #{description}, status = #{status} WHERE id = #{id}; </update> <!--删除商品--> <delete id="deleteById"> DELETE FROM tb_brand WHERE id = #{id}; </delete> </mapper>
-
动态 SQL - 优化 xml文件中的SQL语句,解决较为复杂的SQL语句
-
概述
-
查询 - 动态条件查询
-
- 修改 - 动态修改商品信息
-
批量删除
-
使用注解的测试类
public class MyBatisTest { private static SqlSessionFactory factory; private SqlSession sqlSession; private BrandDao brandDao; @BeforeClass public static void getSQLFactory() throws Exception { //获取核心文件输入流 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); //获取工厂常见对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //获取工厂对象 factory = builder.build(in); } @Before public void getSqlSession() { //获取会话对象 sqlSession = factory.openSession(); //获取代理对象 brandDao = sqlSession.getMapper(BrandDao.class); } @Test public void testSelectByConditions() { //执行操作 Integer status = null; String companyName = "华为"; String brandName = "华为"; Brand brand = new Brand(); brand.setStatus(status); brand.setCompanyName(companyName); brand.setBrandName(brandName); List<Brand> brands = brandDao.selectByConditions(brand); //处理数据 for (Brand brand2 : brands) { System.out.println(brand2); } } @Test public void testUpdateBrand() { //执行操作 Brand brand = new Brand(); brand.setId(11); brand.setBrandName("华为"); brand.setCompanyName("华为"); brand.setOrdered(105); brand.setDescription("最佳公司"); //brand.setStatus(1); brand.setStatus(null); brandDao.updateBrand(brand); sqlSession.commit(); } @Test public void testDeleteByIds() { //执行操作 int[] ids = {7,8,9}; brandDao.deleteByIds(ids); sqlSession.commit(); } @After public void closeSqlSession() { //关闭资源 } }
-
BrandDao.java
public interface BrandDao { //多条件动态查询 List<Brand> selectByConditions(Brand brand); //动态修改商品信息 void updateBrand(Brand brand); //批量删除 void deleteByIds(@Param("ids") int[] ids); }
-
BrandDao.xml
<?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"> <mapper namespace="com.itheima.dao.mapper.BrandDao"> <resultMap id="brandResultMap" type="brand"> <result column="brand_name" property="brandName"></result> <result column="company_name" property="companyName"></result> </resultMap> <!--定义sql片段--> <sql id="selectBrandSql"> SELECT * FROM tb_brand </sql> <!--动态条件查询--> <!--下面的写法,当status为null的时候,会造成sql语句语法错误(where后面跟了一个and)--> <!--<select id="selectByConditions" resultMap="brandResultMap"> SELECT * FROM tb_brand WHERE <if test="status!=null"> status = #{status} </if> <if test="companyName!=null and companyName!=''"> AND company_name LIKE CONCAT('%', #{companyName}, '%'); </if> <if test="brandName!=null and brandName!=''"> AND brand_name LIKE CONCAT('%', #{brandName}, '%') </if> </select>--> <!--可以在where后面跟一个固定的判断条件,在status判断前面加一个and --> <!--这种方式有弊端,如果所有的条件都不满足,会查询到所有的数据--> <!--<select id="selectByConditions" resultMap="brandResultMap"> SELECT * FROM tb_brand WHERE 1=1 <if test="status!=null"> AND status = #{status} </if> <if test="companyName!=null and companyName!=''"> AND company_name LIKE CONCAT('%', #{companyName}, '%') </if> <if test="brandName!=null and brandName!=''"> AND brand_name LIKE CONCAT('%', #{brandName}, '%') </if> </select>--> <!--使用where标签解决语法漏洞--> <!--<select id="selectByConditions" resultMap="brandResultMap"> SELECT * FROM tb_brand <where> <if test="status!=null"> status = #{status} </if> <if test="companyName!=null and companyName!=''"> AND company_name LIKE CONCAT('%', #{companyName}, '%') </if> <if test="brandName!=null and brandName!=''"> AND brand_name LIKE CONCAT('%', #{brandName}, '%') </if> </where> </select>--> <!--trim标签解决语法漏洞--> <!--prefix="where" trim里面的sql语句前面带一个where关键字--> <!--prefixOverrides="and|or" trim里面的sql前面有多余的and或or关键字,就清楚这个关键字--> <!--<include refid="selectBrandSql"></include> 引入一段sql语句--> <select id="selectByConditions" resultMap="brandResultMap"> <include refid="selectBrandSql"></include> <trim prefix="where" prefixOverrides="and|or"> <if test="status!=null"> status = #{status} </if> <if test="companyName!=null and companyName!=''"> and company_name LIKE CONCAT('%', #{companyName}, '%') </if> <if test="brandName!=null and brandName!=''"> and brand_name LIKE CONCAT('%', #{brandName}, '%') </if> </trim> </select> <!--动态修改商品信息--> <!--下面的写法,当status为null的时候,会造成sql语句语法错误(结尾多了一个逗号)--> <!--<update id="updateBrand"> UPDATE tb_brand SET <if test="brandName!=null and brandName!=''"> brand_name=#{brandName}, </if> <if test="companyName!=null and companyName!=''"> company_name=#{companyName}, </if> <if test="ordered!=null"> ordered=#{ordered}, </if> <if test="description!=null and brandName!=''"> description=#{description}, </if> <if test="status!=null "> status=#{status} </if> WHERE id = #{id}; </update>--> <!--set标签--> <!--<update id="updateBrand"> UPDATE tb_brand <set> <if test="brandName!=null and brandName!=''"> brand_name=#{brandName}, </if> <if test="companyName!=null and companyName!=''"> company_name=#{companyName}, </if> <if test="ordered!=null"> ordered=#{ordered}, </if> <if test="description!=null and description!=''"> description=#{description}, </if> <if test="status!=null "> status=#{status} </if> </set> WHERE id = #{id}; </update>--> <!--trim--> <update id="updateBrand"> UPDATE tb_brand <trim prefix="set" suffixOverrides="," suffix="WHERE id = #{id}"> <if test="brandName!=null and brandName!=''"> brand_name=#{brandName}, </if> <if test="companyName!=null and companyName!=''"> company_name=#{companyName}, </if> <if test="ordered!=null"> ordered=#{ordered}, </if> <if test="description!=null and description!=''"> description=#{description}, </if> <if test="status!=null "> status=#{status} </if> </trim> </update> <!--批量删除--> <!-- <delete id="deleteByIds"> delete FROM tb_brand WHERE id in(11,12,13); </delete>--> <!--collection="数组或集合" 实际就是你参数的名字 如果没有在接口中指定参数名,使用默认的arg0参数名--> <!--item="id" 代表集合获数组中每一个数据--> <!--open 与之前语法连接的开始字符--> <!--close 与之后语法连接的结束字符--> <!--separator 多个数据之间的分割字符--> <!-- #{id} 里面的id原则上要与item="id"中的变量名一直--> <delete id="deleteByIds"> DELETE FROM tb_brand WHERE id in <foreach collection="ids" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete> </mapper>
-
注解完成增删改查 - 只能应对比较简单的SQL语句
-
概述
-
例子:查询 - 查看商品详情
-
测试类
public class MyBatisTest { private static SqlSessionFactory factory; private SqlSession sqlSession; private BrandDao brandDao; @BeforeClass public static void getSQLFactory() throws Exception { //获取核心文件输入流 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); //获取工厂常见对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //获取工厂对象 factory = builder.build(in); } @Before public void getSqlSession() { //获取会话对象 sqlSession = factory.openSession(); //获取代理对象 brandDao = sqlSession.getMapper(BrandDao.class); } @Test public void testSelectAll() { List<Brand> brands = brandDao.selectAll(); for (Brand brand : brands) { System.out.println(brand); } } @After public void closeSqlSession() { //关闭资源 } }
-
BrandDao.java
public interface BrandDao { @Select(value = "select * from tb_brand") @ResultMap("brandResultMap") //@ResultMap(value = "brandResultMap") List<Brand> selectAll(); }
-
BrandDao.xml
<?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"> <mapper namespace="com.itheima.dao.mapper.BrandDao"> <resultMap id="brandResultMap" type="brand"> <result column="brand_name" property="brandName"></result> <result column="company_name" property="companyName"></result> </resultMap> </mapper>
-
-
心得
-
整型数据字段用Integer 类型,有助于处理null 的情况,因为从数据库中取数据有可能为空。
-
xml文件写SQL语句时,idea会校验是否正确,你可以在settings中关闭SQL dialect;或者把数据库连接中的 url 具体到要用的数据库。
-
resultMap 用于处理类的属性名与数据库中的字段名不一致的问题,因为不一致查出来会是 null。
-
ResultMap就是ResultType的高级写法,用了resultMap就不写resultType了。
-
Ctrl + Alt + F:把变量定义成全局变量。
-
打印出不同编码的结果,修改引号里的编码方法即可。
-