mybatis学习笔记 day02

MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。它使SQL映射文件与Java代码分离,提高了可维护性,并提供了对象关系映射标签,便于对象关系的建立和维护。此外,MyBatis还支持动态SQL,允许在XML标签内编写动态SQL。常用依赖包括MyBatis本身、MySQL驱动、JUnit、Lombok、Log4j和PageHelper等。在实际使用中,通过配置文件、Mapper接口和XML映射文件实现CRUD操作,同时具备日志记录和分页功能。MyBatis还支持注解方式简化开发,以及通过ResultMap处理属性名和字段名不一致的问题。其一级缓存和二级缓存机制提升了数据访问效率。

mybatis

帮助程序猿将数据存入到数据库中。
方便
传统的JDBC代码太复杂了。简化。框架。自动化。
不用Mybatis也可以。更容易上手。 技术没有高低之分
优点:
1.简单易学
2.灵活
3.sql和代码的分离,提高了可维护性。
4.提供映射标签,支持对象与数据库的orm字段关系映射
5.提供对象关系映射标签,支持对象关系组建维护
6.提供xml标签,支持编写动态sql。

常用依赖

mysql

 <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.12</version>
        </dependency>

mybatis

<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

junit

 <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

lombok

 <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>

log4j

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

pagehelp

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.3.0</version>
</dependency>

mybatis 核心配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tYFe61YN-1659512776286)(C:\Users\黄伟辉\AppData\Roaming\Typora\typora-user-images\image-20220803145712755.png)]

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

   <environments default="development">
        <environment id="development">
            <!-- 配置事务 -->
            <transactionManager type="JDBC"/> <!-- 默认事物管理器 -->
            <dataSource type="POOLED">    <!-- 连接池 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ums?serverTimezone=UTC&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="hx12345678"/>
            </dataSource>
        </environment>
        <!-- 这里还可以配置其他连接 ,<environment id ="mysql12" -->
    </environments>

</configuration>

编写Mybatis配置类

public class Mybatisutils {
  // 会话工厂 创建SqlSession对象,SqlSessionFactory是全局对象 static 保证全局唯一
  public static SqlSessionFactory sqlSessionFactory;

  static {
    try {
      // xml resource资源路径
      String resource = "mybatis.confing.xml";
      // 获得加载核心配置文件的inputStream流
      InputStream inputStream = Resources.getResourceAsStream(resource);
      // 通过SqlSessionFactoryBuilder对象的build方法创建SqlSessionFactory对象
      sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  // 获得 sqlsession
  public static SqlSession getSqlSession() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    return sqlSession;
    // return sqlSessionFactory.openSession();
  }
}

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">
<mapper namespace="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

db.properties

driver=com.mysql.cj.jdbc.Driver
jdbc.url =jdbc:mysql://localhost:3306/ums?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=hx12345678

在 核心配置中  
<properties resource="db.properties"/>

<environments default="development">
        <environment id="development">
            <!-- 配置事务 -->

            <transactionManager type="JDBC"/> <!-- 默认事物管理器 -->
            <dataSource type="POOLED">    <!-- 连接池 -->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
        <!-- 这里还可以配置其他连接 ,<environment id ="mysql12" -->
    </environments>

别名 在核心配置文件中

    <!--可以给实体类起别名-->
    <typeAliases>
        <typeAlias type="com.kuang.pojo.User" alias="User"/>
    </typeAliases>
        <!--可以给实体类起别名   使用第二种方便-->
     <typeAliases>
         <package name="com.kuang.pojo"/>
    </typeAliases>
        

日志 在核心配置 中

<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!-- 标准日志工厂 -->


<!-- log4j 日志工厂-->
  <settings>
     <setting name="logImpl" value="STDOUT_LOGGING"/>
 </settings>

log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
#log4j.appender.file = org.apache.log4j.RollingFileAppender
#log4j.appender.file.File=./log/rzp.log
#log4j.appender.file.MaxFileSize=10mb
#log4j.appender.file.Threshold=DEBUG
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sq1.PreparedStatement=DEBUG

lombok 使用 在实体类 ,不用get set tostring 构造函数

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Film {
    private Integer id;

    private String name;

    private String director;

    private Double price;

    private String pubdate;

    private String company;
}

CRUD操作

public interface usermapper {
    List<User>getusers();

    User getoneuser(String id);

    int addusers(User user);

    /* 使用map */
    int addusers2(Map<String, Object> map);

    int updateusers(User user);

    int deleteusers(String id);
    }

使用xml

<!-- 绑定mapper -->
<!--namespace 要和mapper 同包绑定到指定mapper -->
<mapper namespace="com.powernode.mapper.usermapper">
    <!-- select 中的id 要和 mapper 里面的方法一致,绑定指定方法 -->
    <!-- resultType 是sql 语句执行的返回类型 -->
    <!-- parameterType=""  是参数类型 -->
    <select id="getusers" resultType="com.powernode.entity.User">
        select *
        from user
    </select>
    <select id="getoneuser" parameterType="String" resultType="User">
        select *
        from user
        where usercode = #{id}
    </select>
    <insert id="addusers" parameterType="com.powernode.mapper.usermapper">
        insert into user (usercode,fullname,age,sex,email,address) values(#{usercode},#{fullname},#{age},#{sex},#{email},#{address})
    </insert>

    <update id="updateusers" parameterType="com.powernode.mapper.usermapper" >
        update user set fullname = #{fullname} ,age = #{age} where usercode = #{usercode}
    </update>

    <delete id="deleteusers" parameterType="String" >
        delete from user where usercode = #{usercode}
    </delete>

    <!-- map key 值可以自定义 ,value 里面的和user  区别,就是user需要按照实体类写法 ,map不需要-->
    <insert id="addusers2" parameterType="map">
        insert into user (usercode,fullname,age,sex,email,address) values(#{usercode},#{fullname},#{age},#{sex},#{email},#{address})
    </insert>
    

mapper 绑定 在核心配置文件

<!-- xml  -->
<mappers>
    <mapper resource="com/powernode/mapper/usermapper.xml"/>
</mappers>

<!-- 注解 -->
<mappers>
        <mapper class="com.powernode.mapper.usermapper2"/>
  </mappers>
<!-- mapper 包下所有 mapper  注解和xml 都可以-->	
<mappers>
        <mapper page="com.powernode.mapper.usermapper2"/>
  </mappers>

sql

<!--提取公共的sql 出来    sql id 和 include id 一致-->
    <sql id="commonFile">
        id,name,sex,age,email,address
    </sql>

    <select id="" resultType="" parameterType="">
        select <include refid="commonFile"/> from user
    </select>

解决属性名和字段名不一致的问题

数据库 id name password

实体类 id name psw

sql 语句 : select * from user where id = #{}

输出 psw = null

解决方法:

<select id="getUserById" resultType="User">
    select id,name,password as psw from user where id = #{id}
</select>

ResultMap

id   name   pwd
id   name   password
<!--结果集映射-->
<resultMap id="UserMap" type="User">
    <!--column数据库中的字段,property实体类中的属性-->
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
</resultMap>

<select id="getUserById" resultMap="UserMap">
    select * from user where id = #{id}
</select>

分页 :

使用Limit分页

SELECT * from user limit startIndex,pageSize 

接口:

//分页
List<User> getUserByLimit(Map<String,Integer> map);
<!--分页查询-->
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
    select * from user limit #{startIndex},#{pageSize}
</select>

使用 插件PageHelper :

需要在核心配置文件 中 做 分页拦截

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
select * from user
@Test
public void getuser() {
  int pageNum = 1;
  int pageSize = 5;
  PageHelper.startPage(pageNum,pageSize);
  List<User> userList = usermapper.gerusers();

  PageInfo<User>pageInfo = new PageInfo<>(userList);
  System.out.println("总条数"+pageInfo.getTotal());
  System.out.println("总页数"+pageInfo.getPages());

  List<User> userList1 = pageInfo.getList();
  userList1.forEach(System.out::println);
  sqlSession.close();
}

mybatis 注解

@Delete("delete from user where id = ${uid}")
int deleteUser(@Param("uid") int id);

 @Select("selete * from user where usercode = #{id} and fullname = #{name}")
    User getoneuser2(@Param("id") String id,@Param("name") String name);

关于@Param( )注解
基本类型的参数或者String类型,需要加上
引用类型不需要加
如果只有一个基本类型的话,可以忽略,但是建议大家都加上

一对多处理

一个老师多个学生;
对于老师而言,就是一对多的关系;

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
@Data
public class Teacher {
    private int id;
    private String name;

    //一个老师拥有多个学生
    private List<Student> students;
}
<!--按结果嵌套查询-->
<select id="getTeacher" resultMap="StudentTeacher">
    SELECT s.id sid, s.name sname,t.name tname,t.id tid FROM student s, teacher t
    WHERE s.tid = t.id AND tid = #{tid}
</select>
<resultMap id="StudentTeacher" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <!--复杂的属性,我们需要单独处理 对象:association 集合:collection
    javaType=""指定属性的类型!
    集合中的泛型信息,我们使用ofType获取
    -->
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>


关联 - association 【多对一】
集合 - collection 【一对多】
javaType & ofType
JavaType用来指定实体类中的类型
ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

动态SQL

if示例

<select id="queryBlogIF" parameterType="map" resultType="Blog">
    select * from mybatis.blog where 1=1
    <if test="title != null">
        and title = #{title}
    </if>
    <if test="author != author">
        and author = #{author}
    </if>
</select>

choose、when、otherwise 示例

<select id="queryBlogchoose" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <choose>
            <when test="title != null">
                title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise>
                and views = #{views}
            </otherwise>
        </choose>
    </where>
</select>


trim、where、set 示例

<update id="updateBlog" parameterType="map">
    update mybatis.blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author}
        </if>
    </set>
    where id = #{id}
</update>

for-each 示例

<!--ids是传的,#{id}是遍历的-->
<select id="queryBlogForeach" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <foreach collection="ids" item="id" open="and ("
                 close=")" separator="or">
            id=#{id}
        </foreach>
    </where>
</select>


学习过程中需要注意的小问题:

无法加载配置文件?有可能是找不到这个配置文件

在 pom.xml 中加入

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>

        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.poroperties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

在测试中 明明sql 语句都正确 执行也成功了,可是数据库数据没有变化 增删改

问题是 业务没有提交

在执行完mapper. 操作之后 加上

sqlSession.commit();

@Before @Ater 减少代码重复

public class mapperTest {
  private static SqlSession sqlSession = null;
  private static usermapper usermapper = null;
  private static FilmMapper filmMapper = null;
  @Before
  public void init() {
    sqlSession = Mybatisutils.getSqlSession();
    usermapper = sqlSession.getMapper(usermapper.class);
    filmMapper =sqlSession.getMapper(FilmMapper.class);
  }
  @After
  public void after(){
        sqlSession.commit();
        sqlSession.close();
    }

生命周期和作用域

在这里插入图片描述

SqlSessionFactoryBuilder:

一旦创建了 SqlSessionFactory,就不再需要它了
局部变量

一旦创建了 SqlSessionFactory,就不再需要它了
局部变量

SqlSessionFactory:
说白了就是可以想象为 :数据库连接池
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
因此 SqlSessionFactory 的最佳作用域是应用作用域。
最简单的就是使用单例模式或者静态单例模式。

SqlSession

连接到连接池的一个请求!
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
用完之后需要赶紧关闭,否则资源被占用!

在这里插入图片描述

缓存原理

一级缓存

一级缓存也叫本地缓存:SqlSession
与数据库同一次会话期间查询到的数据会放在本地缓存中
以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

二级缓存

二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
基于namespace级别的缓存,一个名称空间,对应一个二级缓存
工作机制
一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
如果会话关闭了,这个会员对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
新的会话查询信息,就可以从二级缓存中获取内容
不同的mapper查询出的数据会放在自己对应的缓存(map)中
在这里插入图片描述````

笔记资源 狂神说java

mybatis 中文网

jar 包官网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

huangshaohui00

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值