学习Mybatis

学习Mybatis

1.mybatis的介绍

mybatis原是apache的一个开源项目,2010年转投谷歌,从ibtais3.0开始改名为mybatis

mybatis是一个优秀的数据持久层框.
数据持久层(dao)
servlet(web)  接收请求, 调用其他java代码处理, 响应
service 业务逻辑层
dao 数据访问/持久     3层架构

mybatis是对jdbc进行轻量级的封装.
   提供专门xml文件来进行配置,以及可以自动的对查询结果进行封装,
   是一个ORM(java对象与数据库表映射)实现的数据持久层的框架.
   提供一些自己定义的类和接口来实现功能.
   支持动态sql,以及数据缓存.

Mybatis环境搭配以及使用

1).创建一个maven项目,导入mybatis和mysql的jar包

//1.mybatis.jar
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.2</version>
</dependency>
//2.mysql.jar
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.16</version>
</dependency>

2.创建一个数据库表,以及一个应的java模型类

package com.ffyc.jdbcpro.model;

public class Admin {
    private int id;
    private String account;
    private String password;
    private  String adminGender;


    public String getAdminGender() {
        return adminGender;
    }

    public void setAdminGender(String adminGender) {
        this.adminGender = adminGender;
    }

    public Admin() {
        System.out.println("Admin无参构造方法");
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Admin{" +
                "id=" + id +
                ", account='" + account + '\'' +
                ", password='" + password + '\'' +
                ", adminGender='" + adminGender + '\'' +
                '}';
    }
}

3.创建mybatis全局配置文件,配置数据库连接信息

全局配置文件

<?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">
<!--
mybatis核心配置文件
-->
<configuration>

    <properties resource="config.properties"></properties><!--数据库连接池文件-->
    <!-- mybatis设置-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/><!--日志功能-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!--配置类型别名-->
    <typeAliases>
    <!--<typeAlias type="com.ffyc.jdbcpro.model.Admin" alias="Admin"></typeAlias>-->
        <package name="com.ffyc.jdbcpro.model"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED"><!--使用数据库连接池(缓冲池)POOLED/U-->
                <property name="driver" value="${driverName}" />
                <property name="url" value="${url}" />
                <property name="username" value="${uname}" />
                <property name="password" value="${upassword}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mappers/AdminMapper.xml"></mapper>
    </mappers>
</configuration>
3.1数据库连接池

数据库连接池(缓冲池)

现在每与数据库交互一次,创建一个数据库连接对象(Connection,SqlSession),用完就关闭,下一次需要,重复这个过程。问题频繁创建销毁对象需要开销的。

数据库连接池的思想:

可以在启动时设置一个容器,在里面初始化还一些数据库连接对象,请求到来时,可以不用每次都创建销毁,可以重复使用,减少了频繁创建销毁连接对象的开销

一般的设置:

初始连接对象的数量

最大连接对象的数量,

最大的等待时间

3.2设计数库连接池
driverName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssm_db?serverTimezone=Asia/Shanghai
uname=root
upassword=root

4.配置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="接口地址">
    定义 sql 语句
</mapper>

5.定义接口,并且在映射文件中进行访问

public interface AdminDao {
//    接口中的方法名,与xml中的标签id名相同
//    接口中方法参数类型 与xml中的parameterType里面的类型相同
//    接口中方法返回值类型  与xml标签中resultType类型相同
    Admin findAdminById(int id);

}
<?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 namespace="com.ffyc.jdbcpro.dao.AdminDao">
    <select id="findAdminById" resultType="Admin" parameterType="int">
        select id,account,password,admin_gender from admin where id = #{id}
    </select>
</mapper>

   6.测试mybatis

package com.ffyc.jdbcpro.test;

import com.ffyc.jdbcpro.dao.AdminDao;
import com.ffyc.jdbcpro.model.Admin;
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 java.io.IOException;
import java.io.Reader;

public class TestAdmin {
    public static void main(String[] args) throws IOException {
        /*
            配置核心文件
        */
        Reader reader = Resources.getResourceAsReader("mybatis.xml");
        /*
        创建sessionFactory
        SqlSessionFactory封装所有的配置信息,
        SqlSessionFactory负责生成一个数据库链接的会话对象SqlSession对象
        SqlSessionFactory创建开销比较大,所以整个项目中创建一次即可,不用销毁
         */
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//        new SqlSessionFactoryBuilder().build(reader,"word");
        /*
            创建SqlSession session会话,一次与数据库交互,类似于之前使用的Connection
            SqlSessionFactory中的openSession方法用来创建一个SqlSession对象,默认无参的默认设置事物事物为false(手动的)
         */
        SqlSession sqlSession = sessionFactory.openSession();
//        Admin admin1 = sqlSession.selectOne("com.ffyc.findAdminById",1);
//        System.out.println(admin1);
        /*
            现在mybatis
            创建访问接口的代理对象
         */
        AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
        /*
        使用代理对象访问接口中对应方法,本质是调用的是接口对应的sql映射文件中的sql
         */
        Admin admin = adminDao.findAdminById(1);
        System.out.println(admin);
        /*
        关闭与数据库连接对象
         */
        sqlSession.commit();
        sqlSession.close();
    }
}

7进行封装简化代码

package com.ffyc.jdbcpro.util;

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 java.io.IOException;
import java.io.Reader;

public class MybatisUtil {
    static SqlSessionFactory sqlSessionFactory= null;
    static {
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader("mybatis.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*
        创建sessionFactory
        SqlSessionFactory封装所有的配置信息,
        SqlSessionFactory负责生成一个数据库链接的会话对象SqlSession对象
        SqlSessionFactory创建开销比较大,所以整个项目中创建一次即可,不用销毁
         */
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    }
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}
package com.ffyc.jdbcpro.test;

import com.ffyc.jdbcpro.dao.AdminDao;
import com.ffyc.jdbcpro.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.io.IOException;

public class TestAdmin1 {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
        adminDao.findAdminById(1);
        sqlSession.close();
    }
}

8.Sql进行增删改查

增加

<insert id="唯一标识" useGeneratedKeys="把新增加的主键赋值到自己定义的
keyProperty " keyProperty=“ 接收主键的属性 parameterType="参数类型">
    insert into  user(userName,userAge)values(#{userName},#{userAge})
</insert>

删除

<delete id="唯一标识" parameterType="参数类型">
    delete from admin where id= #{id}
</delete>

修改

<update id="唯一标识" parameterType=“参数类型">
    update admin set account= #{account},password= #{password} where id= #{id}
</update>

查询

<select id="唯一标识" resultType="返回结果集类型">
    select * from admin where id= #{id}
</select>
如果java中使用标准驼峰命名,数据库中使用下划线连接命名,可以开始全局
设置实现自动转换
<setting name="mapUnderscoreToCamelCase" value="true"/>
    <select id="findUserInfoById" parameterType="int"resultType="User">
    select * from admin where id=#{id}
</select>
#{}和${}的区别
1.#{参数名}是采用预编译的方式传值的,一般用于向sql中传值使用,更加安全
2.${餐数命}是使用字符串拼接方式传值,不安全,一般用于动态向sql中传列名
组装查询
在进行多表关联处理查询结果一般都是用resulpMap进行查询结果的封装
嵌套查询
出现嵌套时结果不会自动进行映射进行一对多嵌套映射在Mybatis.xml文件中设置
<!--        指定自动映射策略
            NONE:无论是否嵌套,都不会自动映射
            PARTIAL(部分):是mybatis默认值
            FULL:无论是否嵌套,都会进行自动映射
                -->
        <setting name="autoMappingBehavior" value="NONE"/>

但是不管是NONE还是FULL结果都不太理想,但是可以进行手动嵌套映射,分为两种

1.把学生关联的宿舍和操作人信息分别封装到宿舍对象和管理员对象中去,  属于嵌套映射

    <resultMap id="dormMap" type="Dorm">
        <id column="id" property="id"></id>
        <result column="num" property="num"></result>
        <!-- 一个宿舍住了多个学生,需要将多个学生进行映射-->
        <collection property="students" javaType="list" ofType="Student">
            <result column="name" property="name"></result>
            <result column="snum" property="num"></result>
        </collection>
    </resultMap>
    <select id="findDorms" resultMap="dormMap">
          SELECT
              d.id,
              d.num,
              s.name,
              s.num snum
            FROM
              dorm d
              LEFT JOIN student s
                ON d.id = s.dormid
    </select>

collection:嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用处理一对多关联

2.嵌套查询,把一次查询分为多次嵌套

   <!--嵌套查询,把一次查询分为多次嵌套-->

   <resultMap id="studentMap1" type="Student">
       <id column="id" property="id"></id>
       <result column="num" property="num"></result>
       <result column="name" property="name"></result>
       <result column="gender" property="gender"></result>
       <association property="dorm" javaType="Dorm" select="findDormById" column="dormid"></association>
       <association property="admin" javaType="Admin" select="findAdminById" column="adminid"></association>
   </resultMap>

    <select id="findStudentById1" resultMap="studentMap1" parameterType="int">
          select id,num,name,
          gender,dormid,adminid
          from student
          where id  = #{id}
    </select>

    <select id="findDormById" parameterType="int" resultType="Dorm">
        select num from dorm where id  = #{dormid}
    </select>

    <select id="findAdminById" parameterType="int" resultType="Admin">
        select account from admin where id  = #{adminid}
    </select>

association:嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用

注解方式进行增删改查
@Insert : 插入 sql , 和 xml insert sql 语法完全一样
@Select : 查询 sql, 和 xml select sql 语法完全一样
@Update : 更新 sql, 和 xml update sql 语法完全一样
@Delete : 删除 sql, 和 xml delete sql 语法完全一样
@Param : 入参
@Results : 设置结果集合
@Result : 结果
案例
//删除注释
@Delete("delete from student where id = #{id}")
    void deleteStudent(int id);
//新增
    @Insert("insert into student (num,name,gender)value (#{num},#{name},#{gender})")
    void saveStudent(Student student);
//查询
    @Select("select * from student where id = #{id}")
    @Results(id = "stuMap" ,value = {
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "num",property = "num"),

    })
    @ResultMap(value = "stuMap")
    Student findStudent(int id);
Mybatis动态Sql

用于实现动态Sql的元素主要有

if,where,trim,set,choose(when,otherwise),foreach

if对传入条件进行判断

where 元素只会在子元素返回任何内容的情况下才插入 “where” 子句。

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

trim

<!--    trim
        prefix:条件成立时添加指定关键字
        prefixOverrides:条件成立时去掉指定关键字
        -->
    <select id="findStudent" resultType="Student" parameterType="Student">
        select id,num,name,gender from student
            <trim prefix="where" prefixOverrides="add">
                <if test="num!=0">
                    num = #{num}
                </if>
                <if test="name!=null">
                    and name = #{name}
                </if>
                <if test="gender!=null">
                    add gender = #{gender}
                </if>
            </trim>
    </select>

choose:多个添加选择一个进行

    <!--
    choose:
    when:
    otherwise:
    多个条件选择一个
    可以有多个when
     -->
    <select id="findStudent" resultType="Student" parameterType="Student">
        select id,num,name,gender from student
        <trim prefix="where" prefixOverrides="add">
            <choose>
                <when test="num!=0">
                    num = #{num}
                </when>
                <when test="name!=null">
                    name = #{name}
                </when>
                <otherwise>
                    and gender = #{gender}
                </otherwise>
            </choose>
        </trim>
    </select>
set可以动态的根据条件是否成立添加set,可以去除后面得逗号
    <update id="updateStudent" parameterType="Student">
        update student
        <set>
            <if test="num!=0">
                num = #{num},
            </if>
            <if test="name!=null">
                name =#{name},
            </if>
            <if test="gender!=null">
                gender =#{gender}
            </if>
        </set>
        where id = #{id}
    </update>
foreach 元素
主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。foreach
元素的属性主要有 item,index,collection,open,separator,close。
item 表示集合中每一个元素进行迭代时的别名,index 指定一个名字,用于
表示在迭代过程中,每次迭代到的位置,open 表示该语句以什么开始,
separator 表示在每次进行迭代之间以什么符号作为分隔符,close 表示以什
么结束,在使用 foreach 的时候最关键的也是最容易出错的就是 collection
属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的
    <delete id="deleteStudent">
        delete from student where id in 
        <foreach collection="list" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </delete>

特殊符号处理

        xml,html都是标记语言
        类似<,>,&这种不能在sql中使用
        解决办法:1.通过转义符号替换2.以使用<![CDATA[]]>来包裹特殊字符。

转义字符包括:< &lt; >&gt;" &quot;' &apos ;&  &amp

使用<![CDATA[]]>来包裹特殊字符例如:

    <delete id="deleteStudent1">
        delete from student where id<![CDATA[<]]>3
    </delete>

9.Mybatis一级缓存二级缓存

缓存

手机上的缓存 加载图片..... 存在手机本地(内存(机身内存,运行内存))

浏览器中的缓存 访问一些网页,将一些信息缓存到本地(硬盘)

买票/购票缓存 很多人访问 ---数据缓存(运行内存)--> 数据库

缓存作用:为了让程序更快的访问到数据,同时也是为了减少数据库的访问压力可以让数据缓存到内存,手机内存,客户端硬盘中
一级缓存:
mybatis提供一级缓存和二级缓存
    默认开启一级缓存,以及缓存时Sqlsession级别的,当第一次查询数据时将查到的结果封装到Sqlsession对象中
    在同一个sqlsession中执行相同的二次查询时,直接从sqlsession中获取
    一级缓存失效
    sqlsession.close();销毁sqlsession对象
    sqlSession.clearCache();清除缓存中的数据
    新增修改删除会清空缓存数据,flushCache="true"
    public void find(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        Student student = new Student();
//        student.setNum(111);
        student.setName("小红");
        List<Student> list = studentDao.findStudent(student);
        System.out.println("0000");
        sqlSession.clearCache();
        student.setNum(10000);
        List<Student> list1 = studentDao.findStudent(student);
        System.out.println("0000");
        student.setId(1);
        student.setName("小绿");
        student.setNum(10000);
        studentDao.updateStudent(student);
        sqlSession.commit();
        sqlSession.close();
    }
二级缓存
mybatis提供一级缓存和二级缓存
二级缓存:sqlSessionFactory级别,可以实现多个sqlSession共享,
    当第一次查询到数据后,关闭sqlSession时将数据存入到二级缓存中
    二级缓存使用需要进行配置,在setting中配置
    <setting name="cacheEnabled" value="true"/><!--全局开启二级缓存-->
    在 Mapper 映射文件中添加<cache />
    <cache flushInterval="1000"></cache>
    模型类实现序列化接口
    public void find1(){
        SqlSession sqlSession1 = MybatisUtil.getSqlSession();
        StudentDao studentDao1 = sqlSession1.getMapper(StudentDao.class);
        Student student = new Student();
        student.setName("小绿");
        List<Student> list1 = studentDao1.findStudent(student);
        sqlSession1.close();//当关闭sqlsession时会将数据饭给到二级缓存中

        SqlSession sqlSession2 = MybatisUtil.getSqlSession();
        StudentDao studentDao2 = sqlSession2.getMapper(StudentDao.class);
        student.setName("小绿");
        List<Student> list2 = studentDao2.findStudent(student);
        sqlSession1.close();
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值