0%

MyBatis

MyBatis

JavaEE命名规范

  1. 项目名:没有要求,尽量不用中文
  2. 包:公司域名倒写com.zephon
  3. 持久层:dao,persist,mapper
  4. 实体:entity,model,bean,javabean,pojo
  5. 业务逻辑:service,biz
  6. 控制器:controller,servlet,action,web
  7. 过滤器:filter
  8. 异常:exception
  9. 监听器:listener
  10. 注释:
    • 类上和方法上使用文档注释/** */
    • 在方法里面使用/* */或//
    • 类:使用大驼峰(首字母大写,后面每个单词首字母大写)
    • 方法,属性:小驼峰(首字母小写,后面每个单词首字母大写)

框架介绍

框架是什么

框架:软件的半成品,为解决问题制定的一套约束,在提供功能基础上进行扩充

框架中一些不能被封装的代码(变量),需要使用框架者自己新建一个xml文件,在文件中添加变量内容,因此,几乎所有框架,都需要建立特定位置和特定名称的配置文件,这使用的就是xml解析技术和反射技术。

常用概念:

类库:提供的类没有封装一定的逻辑,就像写作文时用的名言警句

框架:有一些约束,就像是模板,只用填空就可以写作文

二者表现形式都是引入jar包

MyBatis简介

  1. Mybatis,开源免费框架,原名叫iBatis
  2. 作用:数据访问层框架,底层是对JDBC的封装
  3. 优点之一是:使用MyBatis时不需要编写实现类,只需要写需要执行的sql命令

MyBatis使用

  1. 导入jar包
  2. 在src下新建全局配置文件,没有名称和地址要求
  3. 在全局配置文件中引入DTD或schema
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- default引用environment的id,当前所使用的环境 -->
<environments default="default">
<!-- 声明可以使用的环境 -->
<environment id="default">
<!-- 事务管理 -->
<!-- 使用原生JDBC事务 -->
<transactionManager type="JDBC"/>

<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///JavaMysql0"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/zephon/mapper/UserMapper.xml"/>
</mappers>
</configuration>
  1. 新建包com.zephon.mapper,在里面新建xml文件,名字建议为实体类Mapper.xml

    文件作用:编写需要执行的SQL命令,可以将xml文件理解成实现类(dao层)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!-- namespace:实现类的全路径(包名+类名) -->
    <mapper namespace="com.zephon.mapper">
    <!-- id:方法名
    parameterType:参数类型
    resultType:返回值类型
    如果方法返回值是list,则需要在resultType中写List泛型,因为mybatis是对jdbc封装,是一行一行读取数据
    如果加了parameterType=“”,“”中没内容就会报错
    -->
    <select id="selAll" resultType="com.zephon.pojo.User">
    select * from ta_user
    </select>
    </mapper>
  2. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class Test {
    public static void main(String[] args) throws IOException {
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

    //使用工厂设计模式
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
    //生产SqlSession
    SqlSession sqlSession = factory.openSession();
    List<User> list = sqlSession.selectList("com.zephon.mapper.selAll");
    for(User u:list){
    System.out.println(u);
    }
    }
    }

环境搭建详解

  1. < transactionManager />type属性可取值
    • JDBC,事务管理使用JDBC原生事务管理方式
    • MANAGED,将事务管理转交给其它窗口,相当于原生JDBC事务setAutoMapping(false);
  2. < dataSource /> type属性值
    • POOLED 使用数据库连接池
    • UNPOOLED 不使用数据库连接池,和直接使用JDBC一样
    • JNDI Java命名目录接口技术

数据库连接池

  1. 在内存中开辟一块空间,存放多个数据库连接对象

  2. JDBC Tomcat Pool,直接由Tomcat产生数据库连接池

  3. 状态

    active :当前连接对象被应用程序使用中

    Idle:空闲状态;等待应用程序使用

  4. 使用数据库连接池的目的:在高频率访问数据库时,使用数据库连接池可以降低服务器系统压力,提升程序运行效率

    小型项目不适用数据库连接池

  5. 实现JDBC tomcat Pool的步骤

    1. 在web项目的META-INF中存放context.xml,写数据库连接池相关属性

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      <?xml version="1.0" encoding="UTF-8"?>
      <Context>
      <Resource
      driverClassName="com.mysql.jdbc.Driver"
      url="jdbc:mysql://localhost:3306/Mysql"
      username="root"
      password=""
      maxActive="50"
      maxIdle="20"
      name="test"
      auth="Container"
      maxWait="10000"
      type="javax.sql.DataSource"
      />
      </Context>
    2. 把项目发布到tomcat中,数据库连接池就产生了

  6. 可以在java中使用jndi获取数据库连接池中的对象

    • Context:上下文接口,context.xml文件对象类型

    • 代码:

      1
      2
      3
      Context cxt = new InitialContext();
      DataSource ds = cxt.lookup("java:com/env/test");
      Connection conn = ds.getConnection();
    • 当关闭连接对象时,是将连接对象归还给数据库连接池,并将状态改为Idle,而非真正关闭

三种查询方式

1
2
3
4
5
6
7
<select id="selAll"  resultType="com.zephon.pojo.User">
select * from ta_user
</select>

<select id="selById" resultType="com.zephon.pojo.User">
select * from ta_user where uid=1
</select>
  1. selectList() 返回值为List< resultType属性控制 >

    适用于查询结果都需要遍历的需求

    1
    2
    3
    4
    List<User> list = sqlSession.selectList("com.zephon.mapper.selAll");
    for(User u:list){
    System.out.println(u.getUid()+u.getUname()+u.getPwd());
    }
  2. selectOne()返回Object

    适用于返回结果只是变量或一行数据时

    1
    2
    User user=sqlSession.selectOne("com.zephon.mapper.selById");
    System.out.println(user.getUname());
  3. selectMap()返回Map

    适用于需要在查询结果中快速通过某列的值取到这行数据的需求

    Map<key,resultType控制>

    1
    2
    Map<Object, Object> map = sqlSession.selectMap("com.zephon.mapper.selById", "uname");
    System.out.println(map);

Log4J

  1. 由apache推出的开源免费日志处理的类库

  2. 为什么需要日志

    1. 在项目中编写System.out.prinln();输出到控制台,当项目发布到tomcat后,没有控制台(在命令行能看见),不容易观察一些输出结果
    2. log4J作用:不仅能把内容输出到控制台,不能把内容输出到文件中,便于观察结果
  3. 使用步骤

    1. 导入jar包
    2. 在src下新建log4j.properties(路径和名称固定)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ### 设置###
    log4j.rootCategory=DEBUG,CONSOLE,LOGFILE
    #log4j.rootLogger = DEBUG,CONSOLE

    ### 输出信息到控制抬 ###
    log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender
    log4j.appender.CONSOLE.Target = System.out
    log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

    ### 输出信息到文件 ###
    log4j.appender.LOGFILE = org.apache.log4j.FileAppender
    log4j.appender.LOGFILE.File = /home/zephon/JetB rains/logs/my.log
    log4j.appender.LOGFILE.Append=true;
    log4j.appender.LOGFILE.layout = org.apache.log4j.PatternLayout
    log4j.appender.LOGFILE.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
    1
    2
    Logger logger = Logger.getLogger(TestLog4j.class);
    logger.debug("testLog4j");
  4. log4j输出级别

    fatal(致命错误)>error(错误)>warm(警告)>info(普通信息)>debug(调试信息)

  5. pattern中常用表达式

    %C:包名+类名

    %d{YYYY-MM-dd HH:mm:ss}:时间

    %L:行号

    %m:信息

    %n:换行

< settings >标签

  1. 在mybatis全局配置文件中通过< settings >标签控制mybatis全局开关

  2. 在mybatis-config.xml中开启log4j

    1
    2
    3
    <settings>
    <setting name="logImpl" value="LOG4J"/>
    </settings>
  3. log4j中可以输出指定内容的日志(控制指定内容)

    1. 命名空间级别(包级别)< mapper >namespace属性中除了最后一个类名,需要在log4j.propeties中先在总体级别调成Error,然后log4j.logger.com.a.b=debug
    2. 类级别
    3. 方法级别

parameterType属性

  1. 在xxxMapper.xml中< select >< delete >等标签的parameterType可以控制参数类型

  2. 在SqlSession的selectXxx()中第二个参数传递中传递参数以实现查询特定数据

  3. 在Mapper.xml中可以通过#{}获取参数

    1. 使用索引,从arg0开始,#{arg0}表示第一个参数
    2. 使用#{param1}表示第一个参数
    3. 如果只有一个参数(基本类型或String),mybatis对#{}里面的内容没有要求只要写内容即可
    1
    2
    3
    <select id="selById" parameterType="int" resultType="com.zephon.pojo.User">
    select * from ta_user where uid=#{0}
    </select>
    1
    2
    User user=sqlSession.selectOne("com.zephon.dao.selById",2);
    System.out.println(user.getUname());
    1. 如果参数是对象,使用#{属性名}
    2. 如果参数是map,写成#{key}
    1
    2
    3
    <select id="selById" parameterType="map" resultType="com.zephon.pojo.User">
    select * from ta_user where uid=#{uid} and uname=#{uname}
    </select>
    1
    2
    3
    4
    5
    6
            //传递多个参数
    Map<String,Object> map = new HashMap<>();
    map.put("uid",3);
    map.put("uname","小王");
    User user=sqlSession.selectOne("com.zephon.dao.selById",map);
    System.out.println(user.getUname());
  4. #{}或${}区别

    1. #{}获取参数的内容支持索引获取,param1获取指定位置参数,并在SQL语句中使用?占位符
    2. \({}字符串拼接,不使用?,默认找\){内容}内容的get/set方法,如果写数字,就是一个数字
    1
    2
    3
    <select id="selById" parameterType="int" resultType="com.zephon.pojo.User">
    select * from ta_user where uid=${uid}
    </select>
    1
    2
    3
    4
    User u = new User();
    u.setUid(2);
    User user=sqlSession.selectOne("com.zephon.dao.selById",u);
    System.out.println(user.getUname());

使用mybatis实现mysql分页

注:?不允许在关键字前后进行数学运算,所以需要在代码中计算完成再传入mapper.xml

1
2
3
<select id="selPage" parameterType="map" resultType="com.zephon.pojo.User">
select * from ta_user limit #{pageStart},#{pageSize}
</select>
1
2
3
4
5
6
7
8
9
10
      //分页
//页大小
int pageSize=2;
//页码
int pageNumber=2;
Map<String,Object> m = new HashMap<>();
m.put("pageSize",pageSize);
m.put("pageStart",pageSize*(pageNumber-1));
List<User> ul = sqlSession.selectList("com.zephon.dao.selPage",m);
System.out.println(ul);

别名

  1. 系统内置别名:把类型全小写(Map->map,List->list,Integer->int)

  2. 给某个类起别名

    1
    2
    3
    <typeAliases>
    <typeAlias type="com.zephon.pojo.User" alias="U"/>
    </typeAliases>
    1
    2
    3
    <select id="selAll"  resultType="U">
    select * from ta_user
    </select>
  3. 直接给某个包下所有类起别名,别名为类名

1
2
3
<typeAliases>
<package name="com.zephon.pojo"/>
</typeAliases>
1
2
3
<select id="selAll"  resultType="User">
select * from ta_user
</select>

MyBatis实现新增

  1. 概念

    1. 功能:从应用程序角度出发,软件具有哪些功能
    2. 业务:完成功能时的逻辑
    3. 事务:从数据库角度出发,完成业务时需要执行的SQL集合,统称一个事务
      • 事务回滚:如果在一个事务中某个SQL执行失败,希望回归到事务的原点,保证数据库数据的完整性
  2. 在mybatis中默认是关闭了JDBC的自动提交功能的

    1. 每一个SqlSession默认都是不自动提交事务
    2. session.commit()提交事务
    3. openSession(true);设置自动提交setAutoCommit(true);
  3. mybatis底层是对JDBC的封装

    1. JDBC中executeUpdate()执行新增,删除,修改的SQL返回值int类型,表示受影响的行数
    2. mybatis中< insert >< delete > < update >标签没有resultType属性,默认返回值为int类型
  4. 在openSession()时,mybatis会创建SqlSession时同时创建一个Transation对象 ,同时autoCommit都为false]

    • 如果出现异常,应该用session.rollback()回滚
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class Test {
    public static void main(String[] args) throws IOException {
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

    //使用工厂设计模式
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
    //生产SqlSession
    SqlSession sqlSession = factory.openSession();
    User u = new User();
    u.setUname("新增");
    u.setPwd("zdf");
    try{
    int index = sqlSession.insert("insUser",u);
    if(index>0){
    System.out.println("成功");
    }else{
    System.out.println("失败 ");
    }
    }catch (Exception e){
    sqlSession.rollback();
    }
    sqlSession.commit();
    sqlSession.close();
    }
    }

Mybatis接口绑定方案及多参数传递

  1. 作用:实现创建一个接口后把mapper.xml由mybatis生成接口的实现类,通过调用接口对象就可以获取mapper.xml中编写的sql

  2. 实现步骤

    1. 创建一个接口
      • 接口包名和接口名与mapper.xml中< mappers>namespace相同
      • 接口中方法名和mapper.xml标签的id属性相同
    2. 在mybatis-config.xml中使用< package>进行扫描接口和mapper.xml
  3. 代码实现

    1. 在mybatis-config.xml中< mappers>下使用< package>

      1
      2
      3
      <mappers>
      <package name="com.zephon.mapper"/>
      </mappers>
    2. 在com.xxx.mapper下新建接口

      1
      2
      3
      public interface UserMapper {
      List<User> selAll();
      }
    3. 在com.xxx.mapper新建一个UserMapper.xml

      1. 其中namespace必须与接口全限定路径(包名+类名)相同
      2. id值必须与接口中方法名相同
      3. 如果接口中方法多个参数,可以省略parameterType
      1
      2
      3
      4
      5
      <mapper namespace="com.zephon.mapper.UserMapper">
      <select id="selAll" resultType="User">
      select * from ta_user
      </select>
      </mapper>
    4. 多参数实现办法

      1. 在接口中声明方法

        1
        2
        3
        4
        5
        6
        7
        8
        //List<User> selByUidName(int uid,String uname);

        /**
        * 没有注解时,对于基本类型,xml中使用只能用param1或arg0
        * 使用注解后,mybatis把参数转换为map了,其中@Param("key")
        * 参数内容就是map的value
        */
        List<User> selByUidName(@Param("uid") int uid,@Param("uname") String uname);
      2. 在mapper.xml中添加

        1
        2
        3
        4
        <!-- 当多参数时,不需要写parameterType -->
        <select id="selByUidName" resultType="User">
        select * from ta_user where uid=#{param1} and uname=#{param2}
        </select>
    5. Test

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      public class Test {
      public static void main(String[] args) throws IOException {
      InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
      SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
      SqlSession session = factory.openSession();
      /**
      * 接口,为什么能实例化?
      * 需要给接口一个实例化对象
      * 使用的是JDK的动态代理设计模式(面向接口的代理设计模式(必须有接口))
      */
      UserMapper userMapper = session.getMapper(UserMapper.class);
      // List<User> list = userMapper.selAll();
      // for (User u : list) {
      // System.out.println(u.getUname()+"-"+u.getPwd());
      // }

      List<User> l = userMapper.selByUidName(1, "小明");
      for (User u : l) {
      System.out.println(u.getUname()+"-"+u.getPwd());

      }
      session.close();
      }
      }

动态SQL

  1. 根据不同的条件需要执行不同的SQL命令,称为动态SQL

  2. Mybatis中动态SQL就是在mapper.xml中添加逻辑判断等

  3. if的使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <select id="selByUnamePwd" resultType="User">
    select * from ta_user where 1=1
    <!-- OGNL表达式,直接写key或对象的属性,不需要添加任何特殊符号 -->
    <if test="uname!=null and uname!=''">
    and uname=#{uname}
    </if>
    <if test="pwd!=null and pwd!=''">
    and pwd=#{pwd}
    </if>
    </select>
  4. where

    1. 当编写where标签时,如果内容中第一个是and,会去掉第一个and
    2. 如果where中有内容会生成where关键字,如果没有内容不生成where关键字
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <select id="selByUnamePwd" resultType="User">
    select * from ta_user
    <where><!-- 其实就是代替了where 1==1,但是效率有提高-->
    <if test="uname!=null and uname!=''">
    and uname=#{uname}
    </if>
    <if test="pwd!=null and pwd!=''">
    and pwd=#{pwd}
    </if>
    </where>
    </select>
  5. choose、when、otherwise

    1. 只要有一个成立,其它都不执行
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <select id="selByUnamePwd" resultType="User">
    select * from ta_user
    <where>
    <choose>
    <when test="uname!=null and uname!=''">
    and uname=#{uname}
    </when>
    <when test="pwd!=null and pwd!=''">
    and pwd=#{pwd}
    </when>
    </choose>
    </where>
    </select>
  6. set用作修改SQL中set从句

    1. 作用:去掉最后一个逗号,如果set里面有内容,生成关键字,否则不生成

    2. 示例:

      1. uid=#{uid}目的是防止< set >中没有内容,mybatis不生成set关键字,如果修改中没有set从句,会有SQL语法错误
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      <update id="upd" parameterType="User">
      update ta_user
      <set>
      uid=#{uid},
      <if test="uname!=null and uname!=''">
      uname=#{uname},
      </if>
      <if test="pwd!=null and pwd!=''">
      pwd=#{pwd},
      </if>
      </set>
      where uid=#{uid}
      </update>
  7. trim

    1. prefix在前面添加内容
    2. prefixOverrides去掉前面内容
    3. suffix在后面添加内容
    4. suffixOverrides去掉后面的内容
    5. 执行顺序:先去掉内容,再添加内容
    1
    2
    3
    4
    5
    6
    7
    <!--- 相当于使用<set> -->
    <update id="upd" parameterType="User">
    update ta_user
    <trim prefix="set" suffixOverrides="," >
    a=a,
    </trim>
    </update>
  8. bind

    1. 作用:给参数重新赋值

    2. 使用场景:

      • 模糊查询
      • 在原内容前或后添加内容
    3. 示例

      1
      2
      3
      4
      <select id="">
      <!-- 模糊查询 -->
      <bind name="uname" value="'%'+uname+'%'"/>
      </select>
  9. foreach

    1. 循环参数内容,还具备在内容的前后添加内容、添加分隔符功能

    2. 适用场景:在in查询中常用,批量新增(mybatis中foreach效率比较低)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      <!-- collection:要遍历的集合
      item:迭代变量,#{迭代变量名}获取内容
      open:循环后左侧添加的内容
      close:循环后右侧添加的内容
      separator:每次循环,元素之间的分隔符
      -->
      <select id="selIn" parameterType="list" resultType="User">
      select * from ta_user where uid in
      <foreach collection="list" item="i" open="(" close=")" separator=",">
      #{i}
      </foreach>
      </select>
  10. sql和include

    1. 某些SQL片段如果希望复用,可以使用< sql>定义这个片段

      1
      2
      3
      <sql id="mysql">
      uid,uname,pwd
      </sql>
    2. 在< select>或< delete>或< update>或< insert>中使用< include>引用

      1
      2
      3
      4
      <select id="">
      select <include refid="mysql"></include>
      from ta_user
      </select>