MyBatis简介、MyBatis入门、MyBatis简单的增删改查操作-day01上

第一节 MyBatis简介

1.1 MyBatis概述

  • MyBatis 原本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对ibatis进行了一些改进。
  • MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  • 对jdbc的封装框架有:Hibernate、dbutils、jdbcTemplate[spring]、mybatis
  • 原理:Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

1.2 以前的jdbc程序代码

package com.it.test;

import org.junit.Test;

import java.sql.*;

/**
 * @ClassName Demo02
 * @Author shuyy
 * @Date 2020/9/18
 **/
public class Demo02 {
    
    

    @Test
    public void test1() {
    
    

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
    
    
            //1.加载数据库驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2.通过驱动管理类获取数据库链接
            connection = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/web-ssh", "root", "root");
            //3.定义sql语句?表示占位符
            String sql = "select * from t_user where username = ?";
            //4.获取预处理statement
            preparedStatement = connection.prepareStatement(sql);
            //5.设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
            preparedStatement.setString(1, "shu");
            //6.向数据库发出sql执行查询,查询出结果集
            resultSet = preparedStatement.executeQuery();
            //7.遍历查询结果集
            while (resultSet.next()) {
    
    
                System.out.println("id:"+resultSet.getString("id") + " 用户名:" + resultSet.getString("username"));
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //8.释放资源
            if (resultSet != null) {
    
    
                try {
    
    
                    resultSet.close();
                } catch (SQLException e) {
    
    
                    e.printStackTrace();
                }
            }
            if (preparedStatement != null) {
    
    
                try {
    
    
                    preparedStatement.close();
                } catch (SQLException e) {
    
    
                    e.printStackTrace();
                }
            }
            if (connection != null) {
    
    
                try {
    
    
                    connection.close();
                } catch (SQLException e) {
    
    
                    e.printStackTrace();
                }
            }
        }
    }
}


在这里插入图片描述

数据库连接频繁开启和关闭,会严重影响数据库的性能。
代码中存在硬编码,分别是数据库部分的硬编码和SQL执行部分的硬编码。

1.3 MyBatis框架的核心

  1. mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的信息
  2. mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂
  3. 通过SqlSessionFactory,可以创建SqlSession会话。Mybatis是通过SqlSession来操作数据库的。
  4. SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)
  5. Executor执行器将要处理的SQL信息封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括HashMap集合对象、POJO对象类型

第二节 Mybatis入门

2.1 环境搭建

1. 下载Mybatis

2. 创建数据库表

  • 在Navicat中创建数据库mybatis_day01,选中该数据库,按F6进入命令行,复制以下sql,enter执行
/*
Navicat MySQL Data Transfer

Source Server         : localhost
Source Server Version : 80013
Source Host           : localhost:3306
Source Database       : mybatis_day01

Target Server Type    : MYSQL
Target Server Version : 80013
File Encoding         : 65001

Date: 2020-09-18 18:14:13
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for items
-- ----------------------------
DROP TABLE IF EXISTS `items`;
CREATE TABLE `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL COMMENT '商品名称',
  `price` float(10,1) NOT NULL COMMENT '商品定价',
  `detail` text COMMENT '商品描述',
  `pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
  `createtime` datetime NOT NULL COMMENT '生产日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of items
-- ----------------------------
INSERT INTO `items` VALUES ('1', '台式机', '10000.0', '电脑质量非常好!', null, '2020-09-18 13:22:53');
INSERT INTO `items` VALUES ('2', '笔记本', '7000.0', '笔记本性能好,质量好!', null, '2020-09-18 13:22:57');
INSERT INTO `items` VALUES ('3', '背包', '500.0', '名牌背包,容量大质量好!', null, '2020-09-18 13:23:02');

-- ----------------------------
-- Table structure for orderdetail
-- ----------------------------
DROP TABLE IF EXISTS `orderdetail`;
CREATE TABLE `orderdetail` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `orders_id` int(11) NOT NULL COMMENT '订单id',
  `items_id` int(11) NOT NULL COMMENT '商品id',
  `items_num` int(11) DEFAULT NULL COMMENT '商品购买数量',
  PRIMARY KEY (`id`),
  KEY `FK_orderdetail_1` (`orders_id`),
  KEY `FK_orderdetail_2` (`items_id`),
  CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`),
  CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of orderdetail
-- ----------------------------
INSERT INTO `orderdetail` VALUES ('1', '3', '1', '1');
INSERT INTO `orderdetail` VALUES ('2', '3', '2', '3');
INSERT INTO `orderdetail` VALUES ('3', '4', '3', '4');
INSERT INTO `orderdetail` VALUES ('4', '4', '2', '3');

-- ----------------------------
-- Table structure for orders
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '下单用户id',
  `number` varchar(32) NOT NULL COMMENT '订单号',
  `createtime` datetime NOT NULL COMMENT '创建订单时间',
  `note` varchar(100) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`),
  KEY `FK_orders_1` (`user_id`),
  CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES ('3', '1', '1000010', '2020-09-18 13:22:35', null);
INSERT INTO `orders` VALUES ('4', '1', '1000011', '2020-09-18 13:22:41', null);
INSERT INTO `orders` VALUES ('5', '10', '1000012', '2020-09-18 13:22:50', null);

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` date DEFAULT NULL COMMENT '生日',
  `sex` char(1) DEFAULT NULL COMMENT '性别',
  `address` varchar(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '王五', '2020-09-18', '2', '南京市');
INSERT INTO `user` VALUES ('10', '张三', '2020-09-18', '1', '北京市');
INSERT INTO `user` VALUES ('27', '张大', '2020-09-18', '1', '上海市');

在这里插入图片描述
在这里插入图片描述

3. 创建项目导包

  1. 创建一个普通的java项目即可(演示一些mybatis的功能)
    在这里插入图片描述
  2. 导入下载好的MyBatis的jar包
    在这里插入图片描述
  • 其中的pdf是mybatis自带的使用教程,从中可以获取一些文件配置。
  1. 导入数据库驱动包
    在这里插入图片描述
  • 发现mybatis里有很多log4j的包

4. 添加log4j.properties

  • Mybatis使用的日志包是log4j的,所以添加log4j.properties。
    在classpath下创建log4j.properties内容如下:【文件内容可以从mybatis-3.2.7.pdf中拷贝】
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

在这里插入图片描述

  • 日志级别在开发阶段设置成DEBUG,在生产阶段设置成INFO或者ERROR。
  • 这里暂不配置写入文件中

2.2 开发步骤

1. 根据需求创建PO(model)类

  • User.java
package com.it.model;

import java.io.Serializable;
import java.util.Date;

/**
 * @ClassName User
 * @Author shuyy
 * @Date 2020/9/19
 **/
public class User implements Serializable {
    
    
    private int id;
    private String username;//用户姓名
    private String sex;//性别,1女2男
    private Date birthday;//生日
    private String address;//地址

	public User() {
    
    
    }
	//id自增无需添加
    public User(String username, String sex, Date birthday, String address) {
    
    
        this.username = username;
        this.sex = sex;
        this.birthday = birthday;
        this.address = address;
    }
    public int getId() {
    
    
        return id;
    }
    public void setId(int id) {
    
    
        this.id = id;
    }
    public String getUsername() {
    
    
        return username;
    }
    public void setUsername(String username) {
    
    
        this.username = username;
    }
    public String getSex() {
    
    
        return sex;
    }
    public void setSex(String sex) {
    
    
        this.sex = sex;
    }
    public Date getBirthday() {
    
    
        return birthday;
    }
    public void setBirthday(Date birthday) {
    
    
        this.birthday = birthday;
    }
    public String getAddress() {
    
    
        return address;
    }
    public void setAddress(String address) {
    
    
        this.address = address;
    }
    @Override
    public String toString() {
    
    
        return "User [id=" + id + ", username=" + username + ", sex=" + sex
                + ", birthday=" + birthday + ", address=" + address + "]";
    }
}

2. 创建全局配置文件SqlMapConfig.xml

  • 名字可以自定义,这里使用SqlMapConfig.xml
  • 在classpath(src)下,创建SqlMapConfig.xml文件【SqlMapConfig.xml(文件头可以从mybatis-3.2.7.pdf文档的2.1.2小节中拷贝)】
<?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>
    <!-- 配置mybatis的环境信息(可配置多个环境,配置多个数据源)-->
    <environments default="development">
        <environment id="development">
            <!-- 配置JDBC事务控制,由mybatis进行管理,如果不配置会报错 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源,采用dbcp连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis_day01"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

3. 编写映射文件

  • 在classpath下,创建sqlmap文件夹。在sqlmap目录下,创建User.xml映射文件。(与hibernate的使用类似)
    【Mybatis的映射文件头(也可以从mybatis-3.2.7.pdf文件中拷贝)】
<?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:命名空间,它的作用就是对SQL进行分类化管理,可以理解为SQL隔离
	注意:使用mapper代理开发时,namespace有特殊且重要的作用
 -->
<mapper namespace="test">
    <!--
        id:statement的id,要求在命名空间内唯一
        parameterType:参数的java类型
        resultType:查询出的单条结果集对应的java类型
        #{}:表示一个占位符 ?
        #{id}:表示该占位符待接收参数的名称为id。注意:如果参数为简单类型时,#{}里面的参数名称可以是任意定义
     -->
    <select id="findUserById" parameterType="int" resultType="com.it.model.User">
		SELECT * FROM USER WHERE id = #{id}
	</select>
</mapper>

在这里插入图片描述

4. 加载映射文件(在SqlMapConfig.xml中配置)

在这里插入图片描述

	<!--加载映射文件-->
    <mappers>
        <mapper resource="com/it/sqlmap/User.xml"></mapper>
    </mappers>

5. 编写测试程序,连接并操作数据库

package com.it.test;

import com.it.model.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 * @ClassName Demo01
 * @Author shuyy
 * @Date 2020/9/19
 **/
public class Demo01 {
    
    
    @Test
    public void test1() throws IOException {
    
    
        //1.读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
        SqlSessionFactoryBuilder sessionFactory = new SqlSessionFactoryBuilder();
        //3.通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession = sessionFactory.build(inputStream).openSession();
        //4.调用SqlSession的操作数据库方法
        //selectOne查询一条记录
        User user = sqlSession.selectOne("findUserById",1);
        System.out.println(user);//查询结果返回的就是一个User对象
        //5.关闭SqlSession
        sqlSession.close();
    }
}

在这里插入图片描述
在这里插入图片描述

2.3 更多操作

1. 模糊查询

在这里插入图片描述

	<!--
		${}:表示拼接SQL字符串
	 	${value}:表示要拼接的是简单类型参数。
		 注意:
		 简单类型:int、byte、...String
		1.如果参数为简单类型时,${}里面的参数名称必须为value
		2.${}会引起SQL注入,一般情况下不推荐使用。但是有些场景必须使用${},比如(排序)order by ${name}
	-->
    <select id="findUserByName" parameterType="String" resultType="com.it.model.User">
		SELECT * FROM USER WHERE username like '%${value}%'
	</select>
  • selectList查询多条记录
    在这里插入图片描述

2. 抽取重复代码(简化书写)

  • 发现每次都要写前面的固定代码,下面来抽取一下,简化书写
package com.it.test;

import com.it.model.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @ClassName Demo02
 * @Author shuyy
 * @Date 2020/9/19
 **/
public class Demo02 {
    
    

    SqlSession sqlSession;

    @Before
    public void before() throws IOException {
    
    
        System.out.println("before...获取session");
        //1.读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
        SqlSessionFactoryBuilder sessionFactory = new SqlSessionFactoryBuilder();
        //3.通过SqlSessionFactory创建SqlSession
        sqlSession = sessionFactory.build(inputStream).openSession();
    }

    @After
    public void after(){
    
    
        System.out.println("after...关闭session");
        //5.关闭SqlSession
        sqlSession.close();
    }
    @Test
    public void test1(){
    
    

        //4.调用SqlSession的操作数据库方法
        //selectList查询多条记录(如果符合结果的记录有多条还使用selectOne会报错哦)
        List<User> list = sqlSession.selectList("findUserByName","张");
        System.out.println(list);//查询结果返回的是一个list集合

    }
}

  • 简化了很多
    在这里插入图片描述

3. 插入

	<!--插入用户信息
    	这里的占位写的是模型的属性,对应一下即可
    -->
	<insert id="insertUser" parameterType="com.it.model.User">
		insert into user (username,sex,birthday,address)
		values (#{username},#{sex},#{birthday},#{address})
	</insert>

在这里插入图片描述

  • 运行成功了,但是数据没有插入,是因为涉及增删改要提交事务(查询不用)
    在这里插入图片描述
	@Test
    public void test2(){
    
    
        //插入
        //4.调用SqlSession的操作数据库方法
        User user = new User("shu", "男", new Date(), "北京市");
        sqlSession.insert("insertUser",user);
        sqlSession.commit();//增删改要提交事务,否则不影响数据库
    }

在这里插入图片描述

在这里插入图片描述

  • sqlSession调用返回的是一个int类型的影响行数
    在这里插入图片描述
    在这里插入图片描述

4. 删除

在这里插入图片描述

	<!--删除用户-->
	<delete id="deleteUserById" parameterType="int">
		delete from user where id = #{id}
	</delete>
	@Test
    public void test3(){
    
    
        //删除用户
        //4.调用SqlSession的操作数据库方法
        int affectRow = sqlSession.delete("deleteUserById", 32);//返回的是一个int类型,受影响的行数
        System.out.println("受影响的行数:"+affectRow);
        sqlSession.commit();//增删改要提交事务,否则不影响数据库
    }

在这里插入图片描述

5. 更新

在这里插入图片描述

	<!--更新用户-->
	<update id="updateUser" parameterType="com.it.model.User">
		update user set username = #{username},birthday = #{birthday},sex = #{sex},address = #{address}
		where id = #{id}
	</update>
	@Test
    public void test4(){
    
    
        //更新
        User user = new User();
        user.setId(29);
        user.setUsername("shu03");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("上海市");
        //4.调用SqlSession的操作数据库方法
        int affectRow = sqlSession.update("updateUser", user);//返回的是一个int类型,受影响的行数
        System.out.println("受影响的行数:"+affectRow);
        sqlSession.commit();//增删改要提交事务,否则不影响数据库
    }

在这里插入图片描述

在这里插入图片描述

6. 插入后自动返回主键(id)

  • MySQL自增主键,是指在insert之前MySQL会自动生成一个自增的主键。
  • 我们可以通过MySQL的函数获取到刚插入的自增主键:LAST_INSERT_ID()
  • 这个函数是在insert语句之后去调用。
    在这里插入图片描述
  • 这里如果使用BEFORE(before)会报错
	<!--插入后自动返回主键id-->
	<insert id="insertUser2" parameterType="com.it.model.User">
		<!--
			selectKey标签:通过select查询来生成主键
			keyProperty:指定存放生成主键的属性
			resultType:生成主键所对应的Java类型
			order:指定该查询主键SQL语句的执行顺序,相对于insert语句
			last_insert_id:MySQL的函数,要配合insert语句一起使用
		-->
		<selectKey keyProperty="id" resultType="int" order="AFTER">
			select LAST_INSERT_ID()
		</selectKey>
		insert into user (username,sex,birthday,address)
		values (#{username},#{sex},#{birthday},#{address})
	</insert>
 	@Test
    public void test5(){
    
    
        //插入后返回主键id
        User user = new User("shu04","男",new Date(),"南京市");
        //4.调用SqlSession的操作数据库方法
        int affectRow = sqlSession.insert("insertUser2", user);//返回的是一个int类型,受影响的行数
        System.out.println("受影响的行数:"+affectRow);
        sqlSession.commit();//增删改要提交事务,否则不影响数据库
        System.out.println("用户的id:"+user.getId());
    }

在这里插入图片描述
在这里插入图片描述

7. 插入后自动返回主键(uuid)

  • 首先要生成一张主键id为uuid类型的表
  • 然后修改id的类型为string,重新提供一下get/set
  • 上面的id是mysql自增机制生成的,无需给id赋值,这里的uuid不同,需要给它赋值,否则报错
    在这里插入图片描述
  • 这里使用的是BEFORE(before使用after会报错)
	<!--插入后自动返回主键uuid-->
	<insert id="insertUser3" parameterType="com.it.model.User">
		<!--
			selectKey标签:通过select查询来生成主键
			keyProperty:指定存放生成主键的属性
			resultType:生成主键所对应的Java类型
			order:指定该查询主键SQL语句的执行顺序,相对于insert语句
		-->
		<selectKey keyProperty="id" resultType="String" order="BEFORE">
			select uuid()
		</selectKey>
		insert into user (id,username)
		values (#{id},#{username})
	</insert>
	@Test
    public void test6(){
    
    
        //插入后返回主键uuid
        User user = new User();
        user.setUsername("shu06");
        //4.调用SqlSession的操作数据库方法
        int affectRow = sqlSession.insert("insertUser3", user);//返回的是一个int类型,受影响的行数
        System.out.println("受影响的行数:"+affectRow);
        sqlSession.commit();//增删改要提交事务,否则不影响数据库
        System.out.println("用户的id:"+user.getId());
    }

在这里插入图片描述

  • 注意它插入的位置,是在上一条记录前(shu05是先插入的)
    在这里插入图片描述

小结

parameterType和resultType

  1. parameterType指定输入参数的java类型,可以写别名或Java类的全限定名。
  2. resultType指定输出结果的java类型,可以写别名或Java类的全限定名。

#{}和${}

  1. #{}:相当于预处理中的占位符?。
  2. #{}里面的参数表示接收java输入参数的名称。
  3. #{}可以接受HashMap、POJO类型的参数。
  4. 当接受简单类型的参数时,#{}里面可以是value,也可以是其它。
  5. #{}可以防止SQL注入
  6. ${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。
  7. ${}会引起SQL注入,所以要谨慎使用
  8. ${}可以接受HashMap、POJO类型的参数。
  9. 当接受简单类型的参数时,${}里面只能是value。

selectOne和selectList

  1. selectOne:只能查询0或1条记录,大于1条记录的话,会报错
  2. selectList:可以查询0或N条记录

猜你喜欢

转载自blog.csdn.net/qq_43414199/article/details/108664200