MyBatis入门级了解

1、MyBatis是什么

​ View ------ Controller ----- Service ----- DAO ------ 数据库

jsp/HTML Servlet/SpringMVC Spring jdbc/dbutils/jdbctemplate/mybatis

mybatis实际上就是 DAO层的一个解决方案

学习过jdbc、dbutils、jdbcTemplate、Hibernate 那么为什么我们还要学习 mybatis呢

JDBC:代码非常复杂、速度快

Hibernate:代码精简、致命的缺点(速度慢)

dbutils、jdbcTemplate:框架都不算 只是对jdbc的一个简单的封装而已

mybatis:他是属于效率处于 JDBC和Hibernate之间

​ 他的代码的复杂度也是趋于 JDBC和Hibernate之间

​ 代码灵活、怎么写都是对的

iBatis和mybatis之间的关系是什么?

ibatis是以前的叫法 mybatis是现在的叫法

2、iBatis能干什么

数据库的访问(CRUD)

整合缓存、还可以给类取别名、IBatis还提供了整合Spring的第三方的包

3、为什么要学习这个iBatis

上面的理由已经很充分了

4、ibatis的简单的使用

4.1、导包
 <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!--第一步:导包-->
        <!--下面就是iBatis的相关的包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>


        <!--mysql的驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.10</version>
        </dependency>

        <!--日志门面-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
4.2、编写mybatis.xml配置文件
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--这个文件的作用:简单的说就是对mybatis的全局配置-->
<configuration>
    <!--
        environments:环境 s    可以配置等多个环境
        这里配置的环境是:数据库的连接信息
        default:如果配置了多个环境 默认使用哪一个环境
    -->
     <environments default="mysql">
         <!--配置一个环境:id:表示的是这个环境的名字
             逻辑意义上是可以随便写的
         -->
         <environment id="mysql">
             <!--配置的是事物的类型  默认配置JDBC就可以了  一般情况下使用的就是这个类型-->
             <transactionManager type="JDBC"></transactionManager>
             <!--这个配置的是数据源  这里你可以认为是固定写法-->
             <dataSource type="POOLED">
                 <property name="driver" value="com.mysql.jdbc.Driver"></property>
                 <property name="url" value="jdbc:mysql:///cd200101"></property>
                 <property name="username" value="root"></property>
                 <property name="password" value="root"></property>
             </dataSource>
         </environment>

       <!--这里是可以配置多个环境的  要使用哪一个环境那么就就配置上面的default就可以了 -->
         <environment id="oracle">
             <transactionManager type=""></transactionManager>
             <dataSource type=""></dataSource>
         </environment>
     </environments>

    <!--在全局配置文件中引入mapper.xml的配置文件-->
    <mappers>
        <mapper resource="UserMapper.xml"></mapper>
    </mappers>
</configuration>
4.3、编写UserMapper.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:命名空间  这个命名空间和其他的命名空间不能重复  一般情况下 实体Mapper
    逻辑上是可以随便写的  但是实际上要见名之意
-->
<mapper namespace="UserMapper">
    <!--insert:表示的是 添加数据到数据库
        id:表示的是方法的名字
        备注:标签之间 就是写SQL语句的地方
    -->
    <insert id="add">
          insert into t_user(userName,password) values('小小波','123');
    </insert>
</mapper>
4.4、编写测试文件
    /**
     * 测试HelloWolrd程序
     */
    @Test
    public void testA() throws IOException {
        //第一步:找到mybatis.xml这个配置文件
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        //第二步:创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        //通过工厂 构建 咋们的SqlSession对象
        //sqlSession这个对象就是用来操作 数据库的对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //接下来就可以操作数据库了
        sqlSession.insert("UserMapper.add");
        //接下来提交和关闭
        sqlSession.commit();
        sqlSession.close();
    }

5、iBatis的基本的增删改查的玩法

5.1、增删改查的玩法
public class Test001 {


    /**
     * 测试HelloWolrd程序
     */
    @Test
    public void testA() throws IOException {
        //第一步:找到mybatis.xml这个配置文件
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        //第二步:创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        //通过工厂 构建 咋们的SqlSession对象
        //sqlSession这个对象就是用来操作 数据库的对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //接下来就可以操作数据库了
        sqlSession.selectOne("UserMapper.delete");

//        System.out.println("查询到的数据是:"+user);
        //接下来提交和关闭
        sqlSession.commit();
        sqlSession.close();
    }


    /**
     * 这里是测试类
     */
    @Test
    public void testAdd(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        sqlSession.insert("UserMapper.add");
        myBatisUtils.close();
    }
    /**
     * 这里是测试类
     */
    @Test
    public void testUpdate(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        sqlSession.insert("UserMapper.update");
        myBatisUtils.close();
    }

    @Test
    public void testQuery(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        Object user = sqlSession.selectOne("UserMapper.queryById");
        System.out.println("对象是:"+user);
        myBatisUtils.close();
    }

    @Test
    public void testDelete(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        Object user = sqlSession.selectOne("UserMapper.delete");
        System.out.println("对象是:"+user);
        myBatisUtils.close();
    }

}

6、iBatis的基本的工具类的使用

public class MyBatisUtils {

     //这个类是可以携程成员变量的
     private SqlSessionFactory sqlSessionFactory=null;
     //保存一个线程局部变量
     private ThreadLocal<SqlSession> threadLocal;

      {
          //需要加载资源
        try {
            threadLocal=new ThreadLocal<>();
            Reader reader = Resources.getResourceAsReader("mybatis.xml");
            sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
        }
      }

    /**
     * 获取操作数据库的对象
     * @return
     */
     public SqlSession getSqlSession(){
         /**
          * 编写访问数据库
          *    1:在一个方法体里面  你调用任何多次数据库  我们只是要求 打开一次数据库 以及关闭一次就可以了
          *    2;简单的说连接是可以重用的
          */
         SqlSession sqlSession = threadLocal.get();
         if(null!=sqlSession){  //说明当前线程不是第一次访问数据库
              return sqlSession;
         }
         //执行到这里 说明是第一次访问数据库
         sqlSession=sqlSessionFactory.openSession();
         //放到线程标记中去
         threadLocal.set(sqlSession);
         return sqlSession;
     }



     public void close(){
         SqlSession sqlSession = threadLocal.get();
         if(null!=sqlSession){
              sqlSession.commit();
              sqlSession.close();
              //将线程的局部变量置为空
             threadLocal.remove();
         }
     }
}

7、iBatis的数据传参的问题

7.1、传递简单参数
    <!--传递简单参数  通过id更新数据
        parameterType:表示的是传进去的参数的数据类型
        这个数据类型有两种写法
           1:写Java中数据类型的全路径   java.lang.String   java.lang.Integer
           2:使用mybatis中的数据类型  这个数据类型与 java中的数据类型是一一对应的
        #{写对应的key的名字}
        简单的数据类型  一个字符串   一个int  一个float  没有key  那么这个时候 这个key是
        可以随便写的 但是为了见名之意   一般写成value
    -->
    <update id="update1" parameterType="string">
        update t_user set password='5555' where userName=#{value}
    </update>

    sqlSession.insert("UserMapper.update1","小波波");
7.2、传递map集合
    <update id="delete" parameterType="map">
       delete from t_user where userName=#{userName} and password=#{password}
    </update>

 Map<String,String> map=new HashMap<>();
        map.put("userName","小波波");
        map.put("password","5555");

        sqlSession.insert("UserMapper.delete",map);
7.3、传递自定义的类的对象
 <!--通过用户名和密码找到用户对象
        表示的是传递的是 用户对象
    -->
<select id="findUserByNameAndPassword"parameterType="com.qf.cd.helloworld.User" resultType="com.qf.cd.helloworld.User">
      select * from t_user t where t.userName=#{userName} and t.password=#{password}
    </select>

 User user = new User(1, "小小波", "123");
         User user1= sqlSession.selectOne("UserMapper.findUserByNameAndPassword",user);


疑问:能不能一次性传递多个简单的参数呢?

因为后面在接受数据的时候 采用的key是随机的 也就说 可以随便写的 假设你传递了多个简单的参数 那么后面如何区分 这个值是哪一个的 呢?

没有办法进行传递 ------ 如果要进行传递 那么你就封装成 map集合 或者 java的类

8、动态SQL的问题

什么是动态SQL? 在进行查询的时候 会根据前端传递数据的条件 来动态的进行SQL语句的拼接的这种方法 就称为动态SQL

需求:前端随地的给定一串id 要求的是 这一串的id的用户信息全部查询出来 这一串id可以是任意的

id:6,7,9 或者 6,7,8,9 或者 7,8,9

select * from t_user where id in(不确定)

动态sql解决的问题

8.1、传递数组来解决问题
<!--动态sql传递数组的问题
        通过一连串的id 找用户对象
         select * from t_user where id in (6,7,8)
         <if>标签用来做条件判断
         如果前端传递的是数组类型的数据  那么 这里使用  list来接受
         遍历数据的时候 那么还是使用 array来做遍历
         collection:表示的是要遍历的这个集合或者数组
         open:sql语句的构成 以什么开始
         close:SQL语句的构成以什么结束
         separator:遍历出来的数据之间使用什么进行分割
         item:每一次遍历出来的数据是什么
         注意:每一次遍历出来的数据 要使用  #{遍历的名字} 去进行获取
    -->
    
    <select id="findUserByIds" parameterType="list" resultType="com.qf.cd.helloworld.User">

        select * from t_user
        <if test="array != null">
            where id
            <foreach collection="array" open="in (" close=")" separator="," item="id">
                #{id}
            </foreach>
        </if>

    </select>
8.2、传递个集合来解决问题
 <!--下面传递集合来解决问题-->
    <select id="findUserByIds2" parameterType="list" resultType="com.qf.cd.helloworld.User">

        select * from t_user
        <if test="list != null">
            where id
            <foreach collection="list" open="in (" close=")" separator="," item="id">
                #{id}
            </foreach>
        </if>

    </select>
8.3、更新数据(插入数据)
 <!--插入数据
        prefix:前缀  拼接的前缀
        suffix:拼接的后缀
        suffixOverrides:这个是去掉结束位置的某一个符号  可以是任意的
        prefixOverrides:去掉开始的符号  这个符号是任意的
    -->
    <insert id="insert222" parameterType="com.qf.cd.helloworld.User">
        insert into t_user
        <trim prefix="(" suffix=")" suffixOverrides="," prefixOverrides="">
            <if test="userName != null">
                userName,
            </if>
            <if test="password !=null">
                password
            </if>
        </trim>

        <trim prefix="values(" suffix=")" suffixOverrides=",">
            <if test="userName != null">
                #{userName},
            </if>
            <if test="password !=null">
                #{password}
            </if>
        </trim>
    </insert>
8.4、动态sql和sql片段
 <select id="findUserByCondition" parameterType="com.qf.cd.helloworld.User" resultType="com.qf.cd.helloworld.User">
        select * from t_user where 1=1
        <if test="userName != null">
            and userName=#{userName}
        </if>
        <if test="password !=null">
            and password=#{password}
        </if>
    </select>

    <select id="findUserByCondition1" parameterType="com.qf.cd.helloworld.User" resultType="com.qf.cd.helloworld.User">
        select * from t_user
        <include refid="xiaobobo"></include>
    </select>

    <!--抽取sql标签
        抽取的sql在任何地方都可以进行调用
    -->
    <sql id="xiaobobo">
        <where>
            <if test="userName != null">
                and userName=#{userName}
            </if>
            <if test="password !=null">
                and password=#{password}
            </if>
        </where>
    </sql>

9、iBatis的结果集的返回问题

9.1、返回简单参数
    <!--返回简单参数
        需求:通过用户名 查询用户id
    -->
    <select id="findIdByUserName" parameterType="string" resultType="int">
        select id from t_user where userName=#{value}
    </select>
    Object id=sqlSession.selectOne("UserMapper.findIdByUserName","小小波");

9.2、返回自定义的类的对象
   <!--返回简单参数
        需求:通过id   查询用户对象
    -->
    <select id="findUserById" parameterType="int" resultType="com.qf.cd.helloworld.User">
        select * from t_user where id=#{value}
    </select>
    Object user=sqlSession.selectOne("UserMapper.findUserById",9);

9.3、返回list集合 但是集合中是常见的数据类型

需求:通过一连串的id查询用户的名字

    <!--返回简单参数
        需求:通过一连串的id 查询一连串的名字
        如果返回集合的数据类型 那么下面的结果集的返回只用写  集合中泛型的数据类型就OK了
    -->
    <select id="findNamesByIds"  resultType="string">
        select userName from t_user where id in(6,7,9)
    </select>
    List<String> strs=sqlSession.selectList("UserMapper.findNamesByIds");
9.4、返回一个集合 集合中的泛型是自定义的类的类型
   <!--
       需求:查询所有的用户
       结果集只是写  泛型中的数据类型就OK了
    -->
    <select id="findUserAll"  resultType="com.qf.cd.helloworld.User">
        select * from t_user
    </select>
    List<User> users=sqlSession.selectList("UserMapper.findUserAll");
9.5、数据库的字段和实体不对应怎么办?
9.5.1、取别名解决这个问题
    <!--字段不对应的问题怎么解决  取别名的解决方案-->
    <select id="findDeptAll"  resultType="com.qf.cd.result.Dept">
        select id as deptId,dept_name as deptName,dept_des as deptDes from t_dept
    </select>

9.5.2、通过结果集映射解决这个问题
 <!--配置结果集的映射关系-->
    <resultMap id="findDeptAll2ResultMap" type="com.qf.cd.result.Dept">
        <!--配置主键映射-->
        <id property="deptId" column="id"></id>
        <!--配置普通字段的映射-->
        <result property="deptName" column="dept_name"></result>
        <result property="deptDes" column="dept_des"></result>
    </resultMap>
    
    <!--字段不对应的问题怎么解决 设置结果集的映射关系-->
    <select id="findDeptAll2" resultMap="findDeptAll2ResultMap">
        select * from t_dept
    </select>

10、注意事项

10.1、增删改的标签或者方法也好、是可以随便换的、因为最终真正的执行的是sql语句、跟调用的方法是没有关系的
10.2、查询的方法一般不能换、因为查询要返回具体查询出来的值、不是返回影响的行数

11、一对一映射的关系

需求:一个用户拥有一个身份证、一个身份证唯一的对应了一个用户

用户------------------身份证----------------->一对一的关系 在查询 用户的时候 我希望的是 能查询出身份证

11.1、先准备用户实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String userName;
    private String password;
    private Idcard idcard;
}

11.2、准备IdCard实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Idcard {
    private int id;
    private Date birthday;
    private String cardNum;
    private int userId;
}
11.3、编写方法的配置
  
    <resultMap id="findUserAllResultMap" type="com.qf.cd.one2one.User">
        <!--配置结果集的映射-->
        <id property="id" column="id"></id>
        <!--配置普通字段的映射-->
        <result property="userName" column="userName"></result>
        <result property="password" column="password"></result>

        <!--接下来配置一对一的映射关系
            property:这个实际上就是 java实体中 对象关系的名字
            javaType:数据类型(全限定名)
        -->
        <association property="idcard" javaType="com.qf.cd.one2one.Idcard">
            <!--配置主键映射-->
            <id property="id" column="idcardId"></id>
            <result property="birthday" column="birthday"></result>
            <result property="cardNum" column="cardNum"></result>
            <result property="userId" column="userId"></result>
        </association>
    </resultMap>
    
    <select id="findUserAll" resultMap="findUserAllResultMap">
        select * from t_user t1,t_idcard t2 where t1.id=t2.userId
    </select>
11.4、测试
    @Test
    public void testAdd(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        List<User> users=sqlSession.selectList("UserMapper.findUserAll");
        System.out.println(users);
        myBatisUtils.close();
    }

12、一对多的映射关系

12.1、准备Dept对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private int deptId;
    private String deptName;
    private String deptDes;
    private List<Employee> emps;

}
12.2、准备Employee对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    private int empId;
    private String empName;
    private int gender;
}
12.3、准备配置文件
    <!--一对多的结果集映射-->
    <resultMap id="findDept1AllResultMap" type="com.qf.cd.one2many.Dept">
        <!--主键映射-->
        <id property="deptId" column="deptId"></id>
        <!--普通字段映射-->
        <result property="deptName" column="deptName"></result>
        <result property="deptDes" column="deptDes"></result>
        <!--一对多的映射-->
        <collection property="emps" ofType="com.qf.cd.one2many.Employee">
            <!--主键字段-->
            <id property="empId" column="empId"></id>
            <!--普通字段-->
            <result property="empName" column="empName"></result>
            <result property="gender" column="gender"></result>
        </collection>
    </resultMap>


    <!--玩一个一对多的映射关系-->
    <select id="findDept1All" resultMap="findDept1AllResultMap">
        select * from t_dept1 t1,t_emp t2 where t1.deptId=t2.deptId
    </select>

12.4、测试
    @Test
    public void testDelete(){
        MyBatisUtils myBatisUtils = new MyBatisUtils();
        SqlSession sqlSession = myBatisUtils.getSqlSession();
        List<Dept> depts=sqlSession.selectList("UserMapper.findDept1All");
        System.out.println(depts);
        myBatisUtils.close();
    }

13、取别名的问题

为什么要整个别名? 因为我们很多时候在写 这个java类型的时候 都写的的全路径

简单的说就是为了解决 传入参数的类型过长 以及 返回参数的类型 过长的问题

mybatis.xml中进行配置

    <!--取别名-->
    <typeAliases>
        <!--
            type:是要取别名的这个java类型
            alias:这个是别名的名字
            别名一般情况下是取给java实体类的  po   dto
        -->
       <!-- <typeAlias type="com.qf.cd.one2many.Dept" alias="deptbobo"></typeAlias>
        <typeAlias type="com.qf.cd.one2many.Employee" alias="empbobo"></typeAlias>-->

        <!--这个就表示的是给这个包里所有的类都取别名
            默认的别名的名字是 类名的首写字母小写
        -->
        <package name="com.qf.cd.one2many"></package>
    </typeAliases>

14、懒加载的问题

14.1、关闭积极的加载、开启懒加载
    <!--iBatis本身的设置 -->
    <settings>
        <!--是否使能延迟的加载 -->
        <setting name="lazyLoadingEnabled" value="true" />
        <!--关闭那个积极的加载 -->
        <setting name="aggressiveLazyLoading" value="false" />
    </settings>

14.2、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:命名空间  这个命名空间和其他的命名空间不能重复  一般情况下 实体Mapper
    逻辑上是可以随便写的  但是实际上要见名之意
-->
<mapper namespace="UserMapper">

    
    <resultMap id="findUserAllResultMap" type="com.qf.cd.one2one.User">
        <!--配置结果集的映射-->
        <id property="id" column="id"></id>
        <!--配置普通字段的映射-->
        <result property="userName" column="userName"></result>
        <result property="password" column="password"></result>

        <!--接下来配置一对一的映射关系
            property:这个实际上就是 java实体中 对象关系的名字
            javaType:数据类型(全限定名)
            column:这个是为了将上面的某一个列的内容给映射下来
            相当于 调用方法的时候要传值
            select:相当于要调用另外的mapper来实现整个逻辑
        -->
        <association property="idcard" column="id" javaType="com.qf.cd.one2one.Idcard" select="IdCardMapper.findIdCardByUserId" fetchType="lazy">
        </association>
    </resultMap>

    <!--玩的是一对一的映射关系-->
    <select id="findUserAll" resultMap="findUserAllResultMap">
        select * from t_user where id=6
    </select>
</mapper>

14.3、测试问题

 @Test
    public void testAdd() throws IOException {
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

        SqlSession sqlSession = sqlSessionFactory.openSession();
        User users=sqlSession.selectOne("UserMapper.findUserAll");

        System.out.println("中国好");
        System.out.println("中国好");
        System.out.println("中国好");
        System.out.println("中国好");
        //执行这一句话的时候才会 执行 IdCard中的sql语句
//        Date birthday = users.getIdcard().getBirthday();
//        System.out.println(birthday);
        sqlSession.commit();
        sqlSession.close();
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值