Mybatis学习笔记

Mybatis

Mybatis是支持普通sql查询,存储过程和高级映射的优秀持久层框架,消除了几乎所有的jdbc代码和参数的手工设置以及结果集的检索,mybatis使用简单的xml或者注解用户配置和原始映射,将接口和java的pojos(plan old java objects)映射成数据库的记录,

ORM:(Object Relations Mapper)
关系对象映射,是为了解决关系型数据库与简单java对象的(POJO)映射关系的一种技术,简单的说就是通过使用ORM扫描对象和数据库之间映射的元数据,将程序中的对象持久化到关系型数据库中

Mybatis是半自动映射工具,和全自动的区别:

Mybatis在查询关联对象,或者关联对象时,需要手动自己写sql语句,所以叫ORM的半自动工具,Hibernate属于全自动映射工具,使用hibrenate进行查询关联对象或者关联集合对象时,可以根据关系模型直接获取,所以叫全自动

传统JDBC开发存在的问题:

频繁的连接对象和释放,容易造成资源的浪费,影响系统性能,可以使用连接池来完成,但是jdbc 的连接池需要自己手动编写;sql语句定义、参数设置、结果集处理存在硬编码,很多项目中sql变化的可能性很大,一旦发生变化,需要修改sql语句,系统需要重新编译、重新发布,维护不容易;使用preparedStatement向占位符传参具有硬编码,因为where条件不一定,可能或多或少对其进行修改,系统不好维护,结果集处理可能存在重复代码,如果用java映射可能会方便很多。

JDBC编程的不足,mybatis如何解决

jdbc会频繁的操作数据库,对数据库频繁连接和额释放,及其消耗系统资源,影响系统的性能,当然使用连接池会解决这一个问题,但是jdbc的连接池要自己写,
mybatis会在xml里面对数据库的连接进行配置,直接映射即可使用
jdbc中的sql语句写在程序中,而现实的sql语句经常会改变,每当改变一次,都需要对程序重新编译,维护不易,
mybatis将sql语句定义在xxxMapper.xml文件中,与java代码分离,
sql语句传参不方便,而where条件不一定,可能多或者少,占位符和条件要一一对应。
mybatis自动将sql语句映射到Java中
对结果集解析麻烦,sql变化导致解析变化,且解析前需要遍历,如果将数据库封装到POJO中会比较方便,
mybatis自动将sql语句映射到java对象

Mybatis优缺点

优点:基于SQL语句编程,相当灵活,不会对数据库的设计和程序造成影响,sql语句写在xml中,实现了sql语句和java的解耦,便于统一管理,提供xml标签,支持编写动态sql,并复用,和jdbc相比消除了大量的代码冗余,并减少了很多代码量,很好的与各种数据库兼容,提供映射标签,支持对象与数据库的的ORM字段的映射关系,提供对象关系映射标签,支持对象关系主键维护,能够和spring集成。适用于专注于SQL本身,是一个足够灵活的DAO层解决方案,对性能要求高,或者需求变化大的项目,比如互联网的项目,是一个不错的选择。
缺点:sql编写量较大,尤其是字段多、关联表多的时候,对开发人员对SQL编写的能力有一定要求,sql依赖数据库,可移植性差,不能随意更换数据库

第一个Mybatis

配置Mybatis
<?xml version="1.0" encoding="UTF-8" ?>


















数据源文件jdbc.properites
driver = com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/200701?characterEncoding=utf8
username=root
password=123456

数据库设计
CREATE DATABASE mybatis;
USE mybatis;

CREATE TABLE user(
id INT(20) NOT NULL PRIMARY KEY,
name VARCHAR(30) DEFAULT NULL,
pwd VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;

insert into user(id,name,pwd) values(1,‘张三’,‘123’),(2,‘tt’,‘123456’),(3,‘yy’,‘789’);

mybatis工具类
package com.ty.tao.utils;

    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.InputStream;

//获取sqlSessionFactory -->SqlSession

public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory;
private static SqlSession sqlSession;
static {
    try {
        //使用mybatis获取sqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        sqlSessionFactory = builder.build(inputStream);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
public static SqlSession getSqlSession(){
    sqlSession = sqlSessionFactory.openSession();
    return sqlSession;
}
}

实体类

package com.ty.tao.pojo;

public class User {
private int id;
private String name;
private String pwd;

public User() {
}

public User(int id, String name, String pwd) {
    this.id = id;
    this.name = name;
    this.pwd = pwd;
}

@Override
public String toString() {
    return "User{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", pwd='" + pwd + '\'' +
            '}';
}

public int getId() {
    return id;
}

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

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getPwd() {
    return pwd;
}

public void setPwd(String pwd) {
    this.pwd = pwd;
}
}

Dao接口

package com.ty.tao.dao;

import com.ty.tao.pojo.User;

import java.util.List;

public interface UserDao {
    List<User> getUserList();
}

接口实现类:变成现在的一个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命名空间:绑定一个dao接口/Mapper接口-->
<mapper namespace="com.ty.tao.dao.UserDao">
<!--cache缓存-->    <!--select id指方法的名字 resultType一个结果 resultMap 结果集-->
<select id="getUserList" resultType="com.ty.tao.pojo.User">
    select * from user
</select>
</mapper>

测试
使用JUnit测试,

@Test
public void test(){
    //1获取sqlSession对象
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    //执行
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    List<User> userList = userDao.getUserList();

    for (User user : userList) {
        System.out.println(user);
    }

    //关闭sqlSession
    sqlSession.close();
}

增删改查

接口编写

//增加一个用户
int addUser(User user);

//万能map集合
int addUser2(Map<String, Object> map);

//更新一个用户
int updateUser(User user);

int updateUser2(Map<String,Object> map);

//删除用户
int deleteUser(int id);

xml编写

<!--对象中的属性可以直接取出-->
<insert id="addUser" parameterType="com.ty.tao.pojo.User">
    insert into user(id,name,pwd) values(#{id},#{name},#{pwd})
</insert>

<!--使用Map集合 userId map的key-->
<insert id="addUser2" parameterType="map">
    insert into user(id,name,pwd) values(#{userId},#{username},#{password})
</insert>

<update id="updateUser" parameterType="com.ty.tao.pojo.User">
    update user set name=#{name},pwd=#{pwd} where id=#{id};
</update>

<!--只修改其中的某一个值,可以通过map集合,传入要修改的值和id即可-->
<update id="updateUser2" parameterType="map">
    update user set name=#{name} where id=#{id};
</update>

<delete id="deleteUser" parameterType="int">
    delete from user where id=#{id}
</delete>

JUint测试

//增删改需要提交事务
@Test
public void addUserTest(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();

    User user = new User(1,"ee","132");

    UserDao mapper = sqlSession.getMapper(UserDao.class);
    int i = mapper.addUser(user);
    sqlSession.commit();
    System.out.println(user);
    System.out.println(i);

    sqlSession.close();
}

@Test
public void updateUserTest(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();

    UserDao mapper = sqlSession.getMapper(UserDao.class);
    int qq = mapper.updateUser(new User(4, "qq", "789789789"));
    System.out.println(qq);
    sqlSession.commit();

    sqlSession.close();
}

@Test
public void deleteUserTest(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    int i = mapper.deleteUser(1);
    System.out.println(i);
    sqlSession.commit();
    sqlSession.close();
}

//测试map 增加
@Test
public void addUser2Test(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();

    UserDao mapper = sqlSession.getMapper(UserDao.class);

    Map<String,Object> map = new HashMap<>();

    map.put("userId",1);
    map.put("username","hello");
    map.put("password","123456");

    int i = mapper.addUser2(map);
    System.out.println(i);
    sqlSession.commit();

    sqlSession.close();
}

@Test
public void updateUser2Test(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();

    UserDao mapper = sqlSession.getMapper(UserDao.class);

    Map<String,Object> map = new ConcurrentHashMap<>();

    map.put("id",2);
    map.put("name","eee");
    int i = mapper.updateUser2(map);
    System.out.println(i);

    sqlSession.commit();
    sqlSession.close();
}

Map
只修改其中的某一个值,可以通过map集合,传入要修改的值和id即可

<update id="updateUser2" parameterType="map">
  update user set name=#{name} where id=#{id};
</update>

使用Map集合 userId map的key

<resultMap id="userListMap" type="com.ty.tao.pojo.User">
    <id property="id" column="id" />
    <result property="name" column="name" />
    <result property="password" column="pwd" />
</resultMap>
<insert id="addUser2" parameterType="map">
  insert into user(id,name,pwd) values(#{userId},#{username},#{password})
</insert>

模糊查询
java代码执行的时候,传递通配符% %

select * from mybatis.user where name like "%" #{value} "%"

sql中拼接

map传递参数,直接再sql中取出key值即可 [parameterType=map]
对象传递参数,直接再sql对象中取对象的属性即可 [parameterType=object]
只有一个基本类型的情况下,直接再sql中取到
多个参数用map或者注解
假设实体类和数据库中参数过多,应该考虑使用map,

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写

两种方式:
1.使用typeAliases标签定义自子标签指定类名,并 确认新的别名

<typeAliases >
    <package name="com.ty.tao.pojo"/>
</typeAliases>

2.使用package 默认类名位包内的类名,首字母小写
3.再实体类少的时候,使用第一种,多的时候使用第二种,但是第一种可以取别名,第二种没有,如果非要改,需要再实体类内加入注解Alises

日志

日志分类
SLF4J
LOG4J 掌握
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING 掌握
NO_LOGGING

mybatis具体使用哪个,在设置中设置

使用STDOUT_LOGGING日志

  <settings>
	<setting name="logImpl" value="STDOUT_LOGGING"/>
 </settings>

在这里插入图片描述
使用LoG4J日志工厂
什么是log4J
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
1.导包

<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>2.12.1</version>
</dependency>

2.编写配置文件 log4j.properites

#将等级为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/ty.log
#输出文件大小,如果超过10m生成一个新的
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
#日志输出级别 都是debug才输出,其他不输出输出对象mybatis  sql Statement ResultSetPreparedStatement
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

配置log4j为日志实现

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

log4j的使用,直接测试运行,
在这里插入图片描述

分页

<select id="getUserListLimit" resultMap="userListMap" parameterType="map" resultType="com.ty.tao.pojo.User">
    select id,name,pwd from mybatis.user limit #{startIndex},#{pageSize}
</select>

测试

@Test
public void getUserListLimitTest(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    Map<String,Integer> map = new ConcurrentHashMap<>();
    map.put("startIndex",0);
    map.put("pageSize",2);
    List<User> userListLimit = mapper.getUserListLimit(map);
    for (User user : userListLimit) {
        System.out.println(user);
    }
    System.out.println(userListLimit);
    sqlSession.close();
}

简单使用
1.在要使用的Log4j的地方 导入Logger 是import org.apache.log4j.Logger下面的
2.日志对象,当前类作为参数对象class
static Logger logger = Logger.getLogger(UserDaoTest.class);

使用注解,不需要编写xml文件

使用注解完成CRUD
1.在工具类中编写自动提交事务
public static SqlSession getSqlSession(){
sqlSession = sqlSessionFactory.openSession(true);
return sqlSession;
}

2.编写接口,使用注解的方式,
//使用注解的方式

@Select("select id,name,pwd password from user")
List<User> getUsers();

//方法内存在多个参数时,需要在参数前面加入@Pram

@Select("select * from user where id=#{id}")
List<User> getOneUserById(@Param("id") int id);

//注解形式增加

@Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
int addOneUser(User user);

//更新

@Update("update user set name=#{name},pwd=#{password} where id=#{id}")
int UpdateOneUser(User user);

//删除

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

测试类:
将接口注册绑定到核心配置文件中

<mappers>
    <mapper class="com.ty.tao.dao.UserDao" />
</mappers>

Lombok

1.下载插件
浏览器下载
2.导入jar包

<dependency>
 <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.12</version>
</dependency>

3.在实体类中加注解

@Alias("hello")
@Data  //定义了get、set、toString、hashcode、equals
@AllArgsConstructor  //定义有参的
@NoArgsConstructor   //定义无参的
public class User {
private int id;
private String name;
private String password;
}

Data最常用:生成get、set、toString、hashcode、equals、无参构造

@Data  //定义了get、set、toString、hashcode、equals
@AllArgsConstructor  //定义有参的
@NoArgsConstructor   //定义无参的

多对一,一对多

create table teacher(
id int(10) not null,
name varchar(20) DEFAULT NULL,
PRIMARY KEY(id)
)ENGINE=INNODB DEFAULT charset=utf8;
INSERT into teacher(id,name) values(1,‘涛老师’)

create table student(
id int(10) not null,
name varchar(30) DEFAULT null,
tid int(10) DEFAULT null,
PRIMARY key (id),
key fktid (tid),
CONSTRAINT fktid FOREIGN key (tid) REFERENCES teacher (id)
)ENGINE=INNODB DEFAULT charset=utf8;

INSERT into student(id,name,tid) values(1,‘小红’,‘1’);
INSERT into student(id,name,tid) values(2,‘小黄’,‘1’);
INSERT into student(id,name,tid) values(3,‘小蓝’,‘1’);
INSERT into student(id,name,tid) values(4,‘小绿’,‘1’);
INSERT into student(id,name,tid) values(5,‘小青’,‘1’);
INSERT into student(id,name,tid) values(6,‘小紫’,‘1’);

按照查询嵌套处理 子查询

<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id" />
<result property="name" column="name" />
<!--复杂属性单独处理 对象:association 集合:connection-->
<association property="teacher" javaType="Teacher" column="tid" select="getTeacher" />
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id}
</select>

方式2

<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid= t.id;
</select>
<resultMap id="StudentTeacher2" type="Student">
<result column="id" property="sid" />
<result column="name" property="sname" />
<association property="teacher" javaType="Teacher" >
    <result property="tname" column="name" />
</association>
</resultMap>

动态sql

什么是动态sql
指:根据不同的条件产生不同的sql语句
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少

CREATE TABLE blog(
id VARCHAR(50) NOT NULL COMMENT ‘博客id’,
title VARCHAR(100) NOT NULL COMMENT ‘博客标题’,
author VARCHAR(30) NOT NULL COMMENT ‘博客作者’,
create_time datetime NOT NULL COMMENT ‘创建时间’,
views INT(30) NOT NULL COMMENT ‘浏览量’
)ENGINE=INNODB DEFAULT charset=utf8

动态sql查询

select * from blog



title = #{title}


and author = #{author}


and views = #{views}



<select id="queryForeachBlog" parameterType="blog" resultType="Blog">
select * from blog
<where>
    <foreach collection="ids" item="id" open="and (" close=")" separator="or">
        id = #{id}
    </foreach>
</where>
</select>

缓存

查询:连接数据库:耗资源
一次查询的结果可以存放在在一个直接可以取到的地方 – >内存 : 缓存
在此查询相同数据库的适合,直接到内存里面就行了

概念:Cache
内存中的临时数据
将用户经常查询的数据防止在缓存(内存)中,用户再去查询数据的时候,不在从数据库中查询,而是从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决高并发系统的性能问题
为什么使用缓存:建设和数据库的交互次数,减少系统开销,提高系统效率
什么样的数据能使用缓存:经常查询并且不经常改变的数据(可以使用缓存)----- 查询

不经常查询并且经常改变的数据 不使用缓存 ----写

二级缓存
二级缓存也叫全局缓存,一级缓存作用域太低,所以诞生了二级缓存,
基于namespace级别的缓存,一个名称空间,对应一个二级缓存
工作机制:
一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
如果当前会话被关闭了,这个会话对应的一级缓存就没有了,但是想要的是当会话关闭的时候,一级缓存中的数据被保存到而二级缓存 中,
新的会话查询信息,就可以从二级缓存中获取,
不同的mapper查询出的数据反正该自己对应的缓存map中

步骤;
1.开启全局缓存
显示的开启二级缓存

2.在要使用二级缓存中mapper开启

<cache
 eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值