MyBatis学习之一----基础了解

1、MyBatis

  数据库有几个表,MyBatis就有多少个mapper.xml文件。可以更方便的对数据库进行增删改查。

  MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

  

 

 根据上图来编写demo

  导入依赖:

  

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.7</version>
        </dependency>

 

  首先创建一个SqlMapConfig.xml,可以比喻为一个食品的配方,记录了连接数据库的信息,以及添加相应的mapper.xml配置文件。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url"
                          value="jdbc:mysql://localhost:3306/zero?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="123" />
            </dataSource>
        </environment>
    </environments>

    <!--配置Mapper的位置-->
    <mappers>
        <mapper resource="mapper.xml"/>
    </mappers>
</configuration>

  测试Mybatis的类

package com.back.mybatis;

import com.back.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.InputStream;

/**
 *
 */
public class MybatisTest {

    @Test
    public void testMybatis()throws Exception{
        //sqlSessionFactory
//        指定一个xml文件位置
        String  resource = "SqlMapConfig.xml";
        //读取文件的时候。默认就是从classes目录开始寻找
        InputStream in = Resources.getResourceAsStream(resource);
//        通过SqlSessionFactoryBuilder构建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//        从sqlSessionFactory中获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //根据ID查询用户,
        // 第一个sql参数:指定sql的唯一标识:名称空间+.对应的sql的id的值
        //第二个参数:传入参数
       User user= sqlSession.selectOne("abc.selectUser",25);
        System.out.println(user);

    }
}

  首先读取SqlMapConfig.xml文件

  然后通过Resources读取进来。

  创建SqlSessionFactory工厂    //SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

  从工厂中获取sqlSession来操作数据库,对其进行增删改查

  mapper.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">
<!--namespace名称空间:当前的xml的唯一标识,只要满足所有mapper中的名称空间不相同即可-->
<mapper namespace="abc">
    <!--#{id}表示要接收的参数,相当于一个?
        id:当前的sql的唯一标识
        resultType:结果集映射的对象的类型,默认的情况下需要书写对象的全路径
    -->
    <select id="selectUser" resultType="com.back.pojo.User">
        select * from user where id = #{id}
    </select>
</mapper>

  类似于Hibernate,需要创建一个pojo的类

  User,实现其的getter和setter方法。

 

 

大概步骤:1、创建配置文件   SqlMapConfig.xml

     2、获取SqlSessionFactory

     3、获取sqlSession

     4、通过sqlSession执行curd操作(需要提前创建mapper.xml(很多的statement /sql语句))并且在SqlMapConfig.xml中引入新创建的mapper(sql语句)

     5、关闭连接sqlSession.commit()

     6、关闭连接.session.close();

 

当User类里的username在数据库中是user_name时,可以使用别名

以上两种都可以

 

 

2、mybatis中dao层的命名规则

  在mybatis中dao层的接口不再使用***Dao 而是修改成***Mapper

  例如:UserDao,修改成UserMapper

思考:像userDao中的代码几乎都只有一行

  

    @Override
    public void addUser(User user) {
        sqlSession.insert("user.addUser",user);
    }

    @Override
    public void deleteUserById(int id) {
        sqlSession.delete("user.deleteUser",id);
    }

  其中的String和id就相当于statement和需要传入进去的参数

  几乎都是固定的格式,那么是否可以不写了呢?

3、动态代理mapper实现类

  需要名称空间为接口的全路径,某一个方法对应的方法名,要和select的id一致。满足这两个要求就可以实现动态代理的实现类。

  

<mapper namespace="com.back.dao.UserDaoService">

    <select id="queryUserById" resultType="com.back.pojo.User">
       select * from user where id = #{id}
    </select>

  就可以不需要接口的实现类,而是直接使用test类来进行。

 

  Namespace的作用:

  Mapper中Namespace的定义本身是没有限制的,只要不重复即可,但是如果要想使用Mybatis提供的DAO的动态代理,namespace必须为DAO接口的全路径,例如:cn.mybatis.dao.UserDAO.

  总结:

  1)Mapper的namespace必须和mapper接口的全路径一致。

  2)Mapper接口的方法名必须和sql定义的id一致。

  3)Mapper接口中方法的输入参数类型必须和sql定义的parameterType一致(不一定)。

  4)Mapper接口中方法的输出参数类型必须和sql定义的resultType一致。

public class UserDaoTest {

    UserDaoService userDaoService;

    SqlSession sqlSession;
    @Before//执行Test方法之前执行
    public void setUp()throws Exception{
        String resouce="SqlMapConfig.xml";
        InputStream inputStream= Resources.getResourceAsStream(resouce);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        sqlSession=sqlSessionFactory.openSession();
        //userDaoService=new UserDaoImpl(sqlSession);
        userDaoService=sqlSession.getMapper(UserDaoService.class);
    }

 

 

4、mybatis-config配置,全局配置信息

 

configuration 配置

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置(settings)和属性(properties)信息。文档的顶层结构如下:

  引入外部文件,properties

  需要在configuration内的最上面。

  4.1properties引入外部文件

<configuration>
    <!--引入外部的properties文件,resource指定文件所在路径-->
    <properties resource="jdbc.properties"></properties>
    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${driverClass}" />
                <property name="url"
                          value="${url}" />
                <property name="username" value="${username}" />
                <property name="password" value="${password}" />
            </dataSource>
        </environment>
    </environments>

  jdbc.properties

  

driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/zero
username=root
password=123

 

4.2settings

  这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。下表描述了设置中各项的意图、默认值等。

  4.2.2    mapUnderscoreToCamelCase   是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 

  java命名规则:驼峰书写,大小写区分两个单词的界限。

  数据库的经典命名规则:两个单词之间使用下划线分割。user_name(因为有的数据库是不区分大小写的,所以在数据库中使用驼峰是没有意义的)

  开启驼峰匹配,就相当于去掉数据库中的下划线,然后再与java中的属性名进行对应。

  

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

  4.2.3  typeAliases

  类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。

 

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

  type指定类的全路径;alias是别名,简写。

  定义一个别名:

  

    <typeAliases>
        <typeAlias type="com.back.pojo.User" alias="User"></typeAlias>
    </typeAliases>

  为一个pojo类指定一个别名或者简称。然后再mapper.xml中可以直接书写简称即可。

  

    <select id="queryUserById" resultType="User">
       select * from user where id = #{id}
    </select>

 

  缺点:需要为每一个类都定义一个类型别名。书写麻烦

  

   也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

  

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。

 简称就是类的名字,并且不区分大小写。

  所以不管写user还是User都可以,但是建议正常书写类的名字。

  mybatis已经为普通的Java类型內建了许多相应的类型别名。它们都是大小写不敏感的。需要注意的是由于重载原始类型的名称所做的特殊处理。所以基本类型不需要书写全路径。

4.3   environments

  

 1     <!-- 和spring整合后 environments配置将废除 -->
 2     <environments default="development">
 3         <environment id="development">
 4             <!-- 使用jdbc事务管理 -->
 5             <transactionManager type="JDBC" />
 6             <!-- 数据库连接池 -->
 7             <dataSource type="POOLED">
 8                 <property name="driver" value="${driverClass}" />
 9                 <property name="url"
10                           value="${url}" />
11                 <property name="username" value="${username}" />
12                 <property name="password" value="${password}" />
13             </dataSource>
14         </environment>
15     </environments>

  mybatis允许配置多个连接环境,default是选择加载哪个环境;

  Mybatis允许配置多个环境,比如说开发环境、测试环境、生成环境,但是在构建SqlSessionFactory时只能选择一个。虽然这种方式也可以做到很方便的分离多个环境,但是在实际使用场景下 我们都是更多的使用Spring来管理数据源,做环境的分离。

 

4.4、mappers映射器

  引入外部的,局部的mappers.xml。告诉MyBatis到哪里去找到这些语句。Java在自动查找这方面没有提供

  

<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

  resource:指定mapper所在文件路径

  mapper中的url

  

<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

  从硬盘上找到xml文件,这种方式基本不用。因为只能在该硬盘上,被定死了。

  

  使用mapper接口类的全路径。

  

<!-- Using mapper interface classes -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
    <mappers>
        <mapper resource="mapper.xml"/>
        <mapper resource="user.xml"/>
        <!--如果使用class方式映射的时候,要求:
        1、mapper.xml和文件的名字和mapper接口的名字一致
        2、要求mapper.xml文件和mapper接口类在一个目录下
        -->
        <mapper class="com.back.dao.UserDaoService"/>
    </mappers>

  但是有两个要求,否则是找不到mapper.xml文件的。

如果接口比较多,配置文件就需要配置多个。

  

  注册所有的接口在一个目录下,

   

<!-- Register all interfaces in a package as mappers -->
<mappers>
  <package name="com.mybatis.mapper"/>
</mappers>

  扫描指定包下面所有的接口,要求:1、要求mapper.xml文件的名字和mapper接口的名字,一致  2、要求mapper.xml文件和mapper接口类在一个目录下

  但是就目前的方法来看还是没有实现xml和java代码分离。需要spring整合后来做处理。

4.5 mybatis-config.xml整理

  1、properties标签-引入外部properties文件。在环境的位置可以使用${key}直接获取properties中的内容。

  2、setting:开启驼峰匹配。

    从数据的经典命名规则到java经典命名规则的映射;把数据库中的下划线去掉和java中的内容进行映射。

  3、typealiases:

 

 

 5、select和insert语句

  如果是insert、update、delete操作,可以直接在方法上定义返回类型Integer。来接受一条sql语句改变的数据库的行数。

  

    /**
     * 增加用户
     */
    public Integer addUser(User user);

  测试代码中
  Integer s=userDaoService.addUser(user1);
  s即为数据库中收到影响的行数

  

    如果想知道addUser的userID是多少可以使用主键回写功能。

  

    <insert id="addUser" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
        INSERT INTO user (id, username, birthday, sex, address) VALUES (NULL, #{username}, NOW(), #{sex}, #{address});
    </insert>

  

useGeneratedKeys:是否开启主键回写
keyProperty:java对象主键的属性名
keyColumn:数据库主键对应的字段的名字
代码
    @Test
    public void TestAddUser(){
        User user1=new User();
        user1.setAddress("北京");
        user1.setUsername("王强");
        user1.setSex(2);
        userDaoService.addUser(user1);
        sqlSession.commit();
        System.out.println(user1.getId());
    }

 

 

 6、#和$

  占位符只能替代指定参数或要传入的值,不能替代表名或者SQL中的关键字。否则会报PersistenceException。

  $属于SQL字符串的拼接。#是指占位符的形式。

  $在取值的时候使用value表示传入的参数的值。所以mapper.xml中

  

    <!--$在取值的时候使用value表示传入的参数的值-->
    <select id="queryUserByTableName" resultType="User">
        select * from ${value}
    </select>

而如果写

  

    <!--$在取值的时候使用value表示传入的参数的值-->
    <select id="queryUserByTableName" resultType="User">
        select * from ${tableName}
    </select>

 

 是会报错的。而且value这种方式不建议书写。因为如果后面有where  value=${value}就无法识别谁代表谁

    <!--在取值的时候使用@Param("tableName")为当前的参数指定一个名字-->
    <select id="queryUserById" resultType="User">
           select * from user where id = #{id}
    </select>
    public List<User> queryUserByTableName(@Param("tableName") String tableName);

 

 7、mybatis传入多个参数parameterType传入参数

  可以使用#{}进行接受一个变量,可以${}接受一个变量

  如果${}没有指定参数名(在方法的参数列表中加入@Param)可以使用${value}表示传递过来的参数

  使用#号的时候是与参数名无关的

   1、使用$去传递参数的时候,使用@Param把参数指定一个名字

   2、如果传入多个参数的时候,使用@Param,一定需要使用为每一个参数都去指定名字

  

    <select id="queryUserById" resultType="User">
           select * from user where id = #{idsfsdafd}
    </select>

  传入多个参数

<!--$在取值的时候使用value表示传入的参数的值
如果传递多个参数,默认情况下是取不到值的
1、使用0、1等一些数字表示传入的参数的顺序并且取值
2、使用param+数字表示传入参数的次序,数字从1开始。
3、使用@param为参数起名字
-->
<select id="queryUserByTableName" resultType="User">
select * from ${tableName} where username=#{username} and password=#{password}
</select>

JAVA代码

  

    public User login(@Param("username"))String username,@Param("password") String password);

推荐使用第三种

8、#{}与${}的区别

  #是占位符

  $是字符串的拼接

  #可以随便写(和参数名无关)

  $使用value取值,或者使用@Param指定一个名字再去取值

在Mybatis的mapper中,参数传递有2种方式,一种是#{}另一种是${},两者有着很大的区别。

  #{}实现的 sql语句的预处理参数。之后执行sql中?号代替,使用时不需要关注数据类型,Mybatis自动实现数据类型的转换。并且可以防止SQL注入。

  ${}实现是sql语句的直接拼接,不做数据类型的转换,需要自行判断数据类型。不能防止SQL注入。

  

1、$字符串拼接,#参数占位相当于jdbc中的?

2、$不能够防止sql注入,#可以防止sql注入的。

3、$可以替换sql语句任何一个内容,#只能替换参数

4、$如果操作字符串,需要在sql中使用单引号。#不需要(不需要判断数据类型)

 

 模糊查询

select * from user where name like '%张%';

 分别用#和$完成一次

#

    <select id="queryUserLikeName1" resultType="User">
        select * from user where username like #{name}
    </select>
    @Test
    public void queryUserLikeName1(){
        List<User> users=userDaoService.queryUserLikeName1("%小%");
        for(User user:users){
            System.out.println(user);
        }
    }

$

    <select id="queryUserLikeName1" resultType="User">
        select * from user where username like '%${name}%'
    </select>
    @Test
    public void queryUserLikeName1(){
        List<User> users=userDaoService.queryUserLikeName1("明");
        for(User user:users){
            System.out.println(user);
        }
    }

  #和$一个是占位符一个是字符串本身的链接操作

  

字符串的拼接操作不能防止SQL注入

  

 那么什么时候用#什么时候用$?

不考虑SQL注入的时候使用$

如果传入的数据,不是sql中的参数的时候,不能够使用#。

通常使用#。

 选择获取参数的时候,首要选择#的方式(1、可以防止SQL注入 2、可以不用考虑数据类型,简化书写3、sql是参数化的SQL,也是预编译的SQL,速度会快一些)

 当#用不了的时候使用$。例如:sql需要改变的是内容是表名的时候,就可使用$方式。

 

 9、ResultMap是Mybatis中最重要最强大的元素,使用它可以解决两大问题:

  POJO属性名和表结构字段名不一致的问题(有些情况下也不是标准的驼峰格式)

   完成高级查询,比如说,一对一、一对多、多对多。

  解决表字段名和属性不一致的问题有两种方法:  

  1、如果是驼峰似的命名规则可以在Mybatis配置文件中设置<setting name="mapUnderscoreToCamelCase" value="true"/>解决

  2、使用ResultMap解决。

  

    <!--id:唯一标识
        type:结果集对应的java类型
        autoMapping:完成数据库字段名到属性名的自动映射,并且支持驼峰规则
    -->
    <resultMap id="userResultMap" type="User" autoMapping="true">
        <!--完成数据库字段名到java对象类型的属性的映射
            id:指定主键的,建议不要省略
            column:数据中字段的名字
            property:java中字段的名字
        -->
        <id column="id" property="id"/>
        <!--result完成部署主键的字段的映射-->
        <result column="user_name" property="username"/>
    </resultMap>

  那么怎么给别人使用呢?

  将

    <select id="queryUserLikeName1" resultType="User">
        select * from user where username like '%${name}%'
    </select>

改为

  

    <select id="queryUserLikeName1" resultMap="userResultMap">
        select * from user where username like '%${name}%'
    </select>

 

 10、SQL片段

  在java代码中会将公用的一些代码提取出来需要的地方直接调用方法即可,在Mybatis也是有类似的概念,那就是SQL片段。

  在Mybatis中使用<sql id="">标签定义SQL片段,在需要的地方通过<include refid=""/>引用,例如:

  

    <sql id="selectUser">
        select * from user
    </sql>

    <select id="queryAllUser" resultType="com.back.pojo.User">
       <include refid="selectUser"></include> where .......
    </select>

  如果我想让其他的mapper.xml文件也使用怎么办。

  可以在外部创建一个xml文件,sql.xml

  不和任何接口映射,只是引入进来。

  sqlMapper.xl文件内容

  

<?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="abc">
    <sql id="selectAllUser">
        select * from user
    </sql>
</mapper>

  需要的时候

    <select id="queryAllUser" resultType="com.back.pojo.User">
       <include refid="abc.selectAllUser"></include>
    </select>

 

 不需要在引入进来,只需要在sqlMapperConfig.xml中引入进来即可。

  

    <!--配置Mapper的位置-->
    <mappers>
        <mapper resource="sqlMapper.xml"/>
        <mapper resource="mapper.xml"/>
        <mapper resource="user.xml"/>
        <!--如果使用class方式映射的时候,要求:
        1、mapper.xml和文件的名字和mapper接口的名字一致
        2、要求mapper.xml文件和mapper接口类在一个目录下
        -->
        <!--<mapper class="com.back.dao.UserDaoService"/>-->
    </mappers>

  

 

 

 

 

 

 

 

  

 

posted @ 2018-01-12 17:14  张小铁  阅读(235)  评论(0编辑  收藏  举报