MyBatis的基本应用

MyBatis的基本应用

​ 它是一款半自动的ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低。

  • ORM
    • Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系,比如用一个Java的Student类,去对应数据库中的一张student表,类中的属性和表中的列一一对应。Student类就对应student表,一个Student对象就对应student表中的一行数据
  • 为什么mybatis是半自动的ORM框架?
    • 用mybatis进行开发,需要手动编写SQL语句。而全自动的ORM框架,如hibernate,则不需要编写SQL语句。用hibernate开发,只需要定义好ORM映射关系,就可以直接进行CRUD操作了。由于mybatis需要手写SQL语句,所以它有较高的灵活性,可以根据需要,自由地对SQL进行定制,也因为要手写SQL,当要切换数据库时,SQL语句可能就要重写,因为不同的数据库有不同的方言(Dialect),所以mybatis的数据库无关性低。虽然mybatis需要手写SQL,但相比JDBC,它提供了输入映射和输出映射,可以很方便地进行SQL参数设置,以及结果集封装。并且还提供了关联查询和动态SQL等功能,极大地提升了开发的效率。并且它的学习成本也比hibernate低很多

快速入门

MyBatis的基本应用_第1张图片

创建数据库

MyBatis的基本应用_第2张图片

添加依赖


<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>5.1.10version>
dependency>

<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.4.6version>
dependency>

<dependency>
    <groupId>junitgroupId>
    <artifactId>junitartifactId>
    <version>4.10version>
    <scope>testscope>
dependency>
<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <version>RELEASEversion>
    <scope>compilescope>
dependency>
<dependency>
    <groupId>log4jgroupId>
    <artifactId>log4jartifactId>
    <version>1.2.17version>
dependency>

<dependency>
    <groupId>com.github.pagehelpergroupId>
    <artifactId>pagehelperartifactId>
    <version>5.1.6version>
dependency>

配置文件

jdbc.properties

db.url=jdbc:mysql://1.117.173.XXX:3306/db?useUnicode=true&characterEncoding=utf-8&erverTimezone=UTC&useSSL=false
db.user=root
db.password=123456
db.driver=com.mysql.jdbc.Driver

log4j.properties

log4j.rootLogger=DEBUG,CONSOLE,file
#log4j.rootLogger=ERROR,ROLLING_FILE
log4j.logger.cn.siliang.dao=debug
log4j.logger.com.ibatis=debug 
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=debug 
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=debug 
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=debug 
log4j.logger.java.sql.Connection=debug 
log4j.logger.java.sql.Statement=debug 
log4j.logger.java.sql.PreparedStatement=debug 
log4j.logger.java.sql.ResultSet=debug 
log4j.logger.org.tuckey.web.filters.urlrewrite.UrlRewriteFilter=debug

# Console Appender
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=error
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern= [%p] %d %c - %m%n

# DailyRolling Fil
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.DatePattern=yyyy-MM-dd
log4j.appender.file.File=log.log
log4j.appender.file.Append=true
log4j.appender.file.Threshold=error
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L)%m%n

mybatis-config.xml

<configuration>
    
    <properties resource="jdbc.properties">properties>

    <settings>
        <setting name="logImpl" value="LOG4J"/>
        <setting name="autoMappingBehavior" value="FULL"/>
    settings>

    <typeAliases>
        <package name="com.test.pojo"/>
    typeAliases>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <property name="helperDialect" value="mysql"/>
        plugin>
    plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                
                <property name="driver" value="${db.driver}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.user}"/>
                <property name="password" value="${db.password}"/>
            dataSource>
        environment>
    environments>

    <mappers>
        
        <mapper resource="./mapper/StudentMapper.xml"/>
    mappers>

configuration>

Mapper(interface)

public interface StudentMapper {

    List<Student> findAll();

    int insert(Student student);

    int delete(Integer id);

    List<Student> findByName(String name);

    List<Student> batchFind(int [] arr);

    int updata(Student student);

    List<Student> findByInfo(Student student);

}

Mapper(xml)


DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.test.dao.StudentMapper">

    <sql id="studentColumn">
        id
        ,name,score,age,gender
    sql>

    <insert id="insert">
        insert into student(name, score, age, gender)
        values (#{name}, #{score}, #{age}, #{gender});
        
        <selectKey keyProperty="id" order="AFTER" resultType="int">
            select LAST_INSERT_ID();
        selectKey>
    insert>

    
    

    
    
    <update id="updata">
        update student
        
        <set>
            <if test="name != null and name != ''">
                name = #{name},
            if>
            <if test="age != null and age gt 0 and age lte 100">
                age = #{age},
            if>
        set>
        where id = #{id}
    update>

    <delete id="delete">
        delete
        from student
        where id = #{id};
    delete>

    <select id="findAll" resultType="com.test.pojo.Student">
        select
        <include refid="studentColumn">include>
        from student;
    select>

    
    <select id="findByName" resultType="com.test.pojo.Student">
        select *
        from student
        where name like '%${value}%';
    select>

    <select id="findByInfo" parameterType="com.test.pojo.Student" resultType="com.test.pojo.Student">
        select
        <include refid="studentColumn">include>
        from student
        <where>
            
            <choose>
                <when test="id != null">
                    and id = #{id}
                when>
                <when test="name != null">
                    and name = #{name}
                when>
                <otherwise>
                    and age = 18
                otherwise>
            choose>
        where>
    select>

    <select id="batchFind" resultType="com.test.pojo.Student" parameterType="java.lang.Integer">
        select * from student
        <where>
            <if test="array != null and array.length > 0">
                and id in
                
                <foreach collection="array" item="id" open="(" separator="," close=")">
                    #{id}
                foreach>
            if>
        where>
    select>

mapper>

Test

public class Test {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    }

    @Test
    public void test() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = mapper.findAll();
        studentList.forEach(System.out::println);
    }

    @Test
    public void test1() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        Student student = new Student();
        student.setName("zs");
        student.setAge(18);
        student.setScore(1);
        student.setGender(1);
        System.out.println(mapper.insert(student));
        System.out.println(student.getId());
        sqlSession.commit();
    }

    @Test
    public void test2() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        System.out.println(mapper.delete(7));
        sqlSession.commit();
    }

    @Test
    public void test3() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List<Student> list = mapper.findByName("李状");
        list.forEach(System.out::println);
    }

    @Test
    public void test4() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List<Student> list = mapper.batchFind(new int[]{1,2,3,4,5,6});
        list.forEach(System.out::println);
    }

    @Test
    public void test5() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        System.out.println(mapper.updata(new Student(9, "zsss", 0, 0, 0)));
        sqlSession.commit();
    }

    @Test
    public void test6() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> list = mapper.findByInfo(new Student(null, null, 0, 0, 0));
        list.forEach(System.out::println);
    }
}

配置文件简述

​ 全局配置文件中,各个标签要按照如下顺序进行配置,因为mybatis加载配置文件的源码中是按照这个顺序进行解析的。

<configuration>
	
configuration>

#{}和${}的区别

​ 一般会采用#{}#{}在mybatis中,最后会被解析为?,作为占位符,其实就是Jdbc的PreparedStatement中的?占位符,它有预编译的过程,会对输入参数进行类型解析(如果入参是String类型,设置参数时会自动加上引号),可以防止SQL注入。

​ 如果parameterType属性指定的入参类型是简单类型的话(简单类型指的是8种java原始类型再加一个String),#{}中的变量名可以任意,如果入参类型是pojo,比如是Student类那么#{name}表示取入参对象Student中的name属性,#{age}表示取age属性,这个过程是通过反射来做的,这不同于${}${}取对象的属性使用的是OGNL(Object Graph Navigation Language)表达式。

​ 而${},一般会用在模糊查询的情景,比如SELECT * FROM student WHERE name like '%${name}%';它的处理阶段在#{}之前,它不会做参数类型解析,而仅仅是做了字符串的拼接,若入参的Student对象的name属性为zhangsan,则上面那条SQL最终被解析为SELECT * FROM student WHERE name like '%zhangsan%';而如果使用的是#{},这条SQL最终就会变成SELECT * FROM student WHERE name like '%'zhangsan'%';所以模糊查询只能用${}

​ 虽然普通的入参也可以用${},但由于${}不会做类型解析,就存在SQL注入的风险。比如,虽然普通的入参也可以用${},但由于${}不会做类型解析,就存在SQL注入的风险,因为OR '1' = '1'恒成立,这样攻击者在不需要知道用户名和密码的情况下,也能够完成登录验证。

​ 另外,对于pojo的入参,${}中获取对象属性的语法和#{}几乎一样,但${}在mybatis底层是通过OGNL表达式语言进行处理的,这跟#{}的反射处理有所不同。对于简单类型(8种java原始类型再加一个String)的入参,${}中参数的名字必须是valueSELECT count(1) FROM user WHERE name like '%${value}%'

缓存

一级缓存

​ 默认开启,同一个SqlSesion级别共享的缓存,在一个SqlSession的生命周期内,执行2次相同的SQL查询,则第二次SQL查询会直接取缓存的数据,而不走数据库,当然,若第一次和第二次相同的SQL查询之间,执行了DML(INSERT/UPDATE/DELETE),则一级缓存会被清空,第二次查询相同SQL仍然会走数据库。
​ 一级缓存在下面情况会被清除:

  • 在同一个SqlSession下执行增删改操作时(不必提交),会清除一级缓存
  • SqlSession提交或关闭时(关闭时会自动提交),会清除一级缓存
  • 对mapper.xml中的某个CRUD标签,设置属性flushCache=true,这样会导致该MappedStatement的一级缓存,二级缓存都失效(一个CRUD标签在mybatis中会被封装成一个MappedStatement)
  • 在全局配置文件中设置 ,这样会使一级缓存失效,二级缓存不受影响

二级缓存

​ 默认关闭,可通过全局配置文件中的开启二级缓存总开关,然后在某个具体的mapper.xml中增加,即开启了该mapper.xml的二级缓存。二级缓存是mapper级别的缓存,粒度比一级缓存大,多个SqlSession可以共享同一个mapper的二级缓存。注意开启二级缓存后,SqlSession需要提交,查询的数据才会被刷新到二级缓存当中

关联查询

pojo

Stu

@Data
public class Stu {
    private Integer id;
    private String name;
    //多个学生可以是同一个老师,即多对一
    private Teacher teacher;
    //老师对学生   -对多
    private Integer tid;
}

Teacher

@Data
public class Teacher {
   private Integer id;
   private String name;
   //一个老师多个学生
   private List<Stu> stus;
}

Interface

public interface StuMapper {

    List<Stu> findAll();

    List<Stu> findAll2();
}

public interface TeacherMapper {

    public Teacher getTeacher(Integer id);

}

xml

StuMapper.xml


DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.test.dao.StuMapper">

    
    <select id="findAll" resultType="stu" resultMap="StuTeacher">
        select *
        from stu
    select>
    <resultMap id="StuTeacher" type="stu">
        
        <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
    resultMap>
    
    <select id="getTeacher" resultType="teacher">
        select *
        from teacher
        where id = #{id}
    select>
    

    
    <select id="findAll2" resultType="stu" resultMap="StuTeacher2">
        select
            s.id sid, s.name sname, t.id tid, t.name tname
        from stu s
        join teacher t
        on s.tid = t.id
    select>
    <resultMap id="StuTeacher2" type="stu">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="teacher">
            <id property="id" column="tid"/>
            <result property="name" column="tname"/>
        association>
    resultMap>
mapper>

Teacher.xml


DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.test.dao.TeacherMapper">

    
    <select id="getTeacher" resultMap="TeacherStu">
        select
            t.id tid, t.name tname, s.id sid, s.name sname
        from stu s
                 join teacher t on s.tid = t.id
        where t.id = #{id}
    select>
    <resultMap id="TeacherStu" type="teacher">
        <id property="id" column="tid"/>
        <result property="name" column="tname"/>
        <collection property="stus" ofType="stu">
            <id property="id" column="sid"/>
            <result property="name" column="sname"/>
        collection>
    resultMap>
mapper>

Test(分页)

public class Test{

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    }

    /**
     * 一对多
     */
    @Test
    public void test() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StuMapper mapper = sqlSession.getMapper(StuMapper.class);
        List<Stu> list = mapper.findAll();
        list.forEach(System.out::println);
    }

    /**
     * 一对多
     */
    @Test
    public void test1() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StuMapper mapper = sqlSession.getMapper(StuMapper.class);
        List<Stu> list = mapper.findAll2();
        list.forEach(System.out::println);
    }

    /**
     * 多对一
     */
    @Test
    public void test2() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);
    }

    /**
     * 分页
     */
    @Test
    public void test3() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //开启分页
        PageHelper.startPage(1, 2);
        StuMapper mapper = sqlSession.getMapper(StuMapper.class);
        List<Stu> list = mapper.findAll2();
        PageInfo<Stu> pageInfo = new PageInfo<>(list);
        System.out.println("获取总数:" + pageInfo.getTotal());
        list.forEach(System.out::println);
    }
}

Mapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
}

/**
 * 分页
 */
@Test
public void test3() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //开启分页
    PageHelper.startPage(1, 2);
    StuMapper mapper = sqlSession.getMapper(StuMapper.class);
    List list = mapper.findAll2();
    PageInfo pageInfo = new PageInfo<>(list);
    System.out.println("获取总数:" + pageInfo.getTotal());
    list.forEach(System.out::println);
}

}


你可能感兴趣的:(mybatis,java,sql)