Mybatis小结

1.Mybatis简介

1.1 MyBatis介绍

​ MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对ibatis进行一些改进。 现在托管到gitHub上,下载:https://github.com/mybatis/mybatis-3/releases

​ MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

​ Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

​ Mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)

Mybatis的文档:https://mybatis.org/mybatis-3/zh/getting-started.html

1.2 Mybatis框架执行流程

在这里插入图片描述

  1. 读取MyBatis 配置文件mybatis-config.xml,加载数据源、事务等
  2. 加载映射文件mapper.xml
  3. 定义SQL语句,在上一步的文件中加载。
  4. 创建会话工厂。(SqlSessionFactory)
  5. 创建会话(SqlSession)
  6. 通过Executor 操作数据库
  7. 输入参数和输出结果

2. Mybatis 入门程序

2.1 需求

  • 根据用户id(主键)查询用户信息

  • 根据用户名称模糊查询用户信息

  • 添加用户

  • 删除用户

  • 更新用户

2.2 环境搭建

sql语句:

CREATE TABLE tb_user(
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(20),
  password VARCHAR(50),
  sex VARCHAR(2),
  brithday DATE,
  address VARCHAR(200)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

log4j.properties

    #在开发阶段使用debug,在生产环境设置为info或者error
    log4j.rootLogger=debug,console

    #控制台输出
    log4j.appender.console=org.apache.log4j.ConsoleAppender
    log4j.appender.console.layout=org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%n

添加如下依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
     <groupId>com.suke</groupId>
     <version>1.0-SNAPSHOT</version>
    <artifactId>mybatis-demo1</artifactId>

    <!--添加mybatis的依赖-->
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <!--mysql的数据库驱动jar-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

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

        <!--log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    
    </dependencies>

</project>

2.3 Mybatis的主配置文件 mybatis-config.xml

mybatis-config.xml主要用来配置mybatis的运行环境,数据源、事务等。

在classpath下创建mybatis-config.xml,如下:

<?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>
    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <!-- 可以配置多个environment -->
        <environment id="development">
            <!-- 使用jdbc事务管理-->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/shopdb" />
                <property name="username" value="root" />
                <property name="password" value="123" />
            </dataSource>
        </environment>
    </environments>
</configuration>

注意: 如果使用mysql8de驱动,数据库四大参数:

<environment id="development">
      <!-- 使用jdbc事务管理-->
      <transactionManager type="JDBC" />
      <!-- 数据库连接池-->
      <dataSource type="POOLED">
          <property name="driver" value="com.mysql.cj.jdbc.Driver" />
          <property name="url" value="jdbc:mysql://localhost:3306/shopdb?serverTimezone=Asia/Shanghai" />
          <property name="username" value="root" />
          <property name="password" value="123" />
      </dataSource>
  </environment>

2.4 根据用户id(主键)查询用户信息

编写User实体类

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

@Data
public class User{
    //实例类的属性的数据类型写包装类型
    private Integer userId;
    private String name;
    private String password;
    private String sex;
    //实体类的日期类型一定使用java.util.Date
    private Date  brithday;
    private String address;

}

2.5 sql映射文件

映射文件命名:

User.xml(原始ibatis命名),mapper代理开发映射文件名称叫XXXMapper.xml,比如:UserMapper.xml、ItemsMapper.xml.在映射文件中配置sql语句。

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命名空间,作用就是对sql进行分类管理
	注意:使用mapper代理方法开发时,namespace需要特殊设置
 -->
<mapper namespace="test">
</mapper>

在UserMapper.xml中添加sql语句

<!-- 根据id获取用户信息 -->
	<select id="findUserById" parameterType="int" resultType="org.csmf.mybatis.entity.User">
		select * from t_user where id = #{id}
	</select>

parameterType:定义输入到sql中的映射类型,#{id}表示使用preparedstatement设置占位符号并将输入变量id传到sql。

resultType:定义结果映射类型。

2.6 将sql映射文件添加到MyBatis主配置文件中

mybatis框架需要加载映射文件,将UserMapper.xml添加到mybatis-config.xml中

<mappers>
	<mapper resource="UserMapper.xml"/>
</mappers>

2.7 测试程序

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

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 org.csmf.mybatis.entity.User;
import org.junit.Test;

/**
 * 测试使用Mybatis操作数据库
 * @author pactera
 *
 */
public class UserDaoTest {
	@Test
	public void testFindUserById(){
		InputStream inputStream = null;
		try {
			//0.加载Mybatis的主配置文件
			// Resources.getResourceAsStream()获取classpath下面的资源
			inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		} catch (IOException e) {
			e.printStackTrace();
		}
		//1.通过Mybatis的主配置文件得到SqlSessionFactory对象
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		//2.通过SqlSessionFactory得到SqlSession
		SqlSession sqlSession = sqlSessionFactory.openSession();
		//3.通过SqlSession操作数据库
		//selectOne(): 
		//第一个参数是Statement的Id也就是sql映射文件中的select,insert,,标签的Id 
		//第二个参数是输入参数
		User user = sqlSession.selectOne("findUserById",2);
		//输出
		System.out.println(user.getUsername()+"-->"+user.getBrithday());
         //4.关闭SqlSession
         sqlSession.close();
	}
}

2.8 根据用户姓名模糊查询

<!-- 根据姓名模糊查询 -->
	<select id="findUserByName" parameterType="string" resultType="org.csmf.mybatis.entity.User">
		select * from tb_user where username like #{name}
	</select>

2.9 添加用户

	<!-- 添加用户 -->
	<!-- 
		parameterType: 输入参数为Java对象类型
		如果输入参数为java对象类型 #{}中只能写的是Java对象的属性名,不能随意写
		注意:如果主键是自增长,不能手动赋值
	 -->
	<insert id="addUser" parameterType="org.csmf.mybatis.entity.User">
		insert into tb_user(username,password, sex,birthday, address)
	values(#{username},#{password},#{sex},#{brithday},#{address})
	</insert>

如果想得到自增列产生的id值,我们可以进行如下配置:

 <insert id="insert">
        <selectKey resultType="int" order="AFTER" keyProperty="id">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into tb_userinfo(name,gender,age,address,email,qq,photo)
        values(#{name,jdbcType=VARCHAR},#{gender,jdbcType=VARCHAR},#{age,jdbcType=INTEGER},#{address,jdbcType=VARCHAR}
        ,#{email,jdbcType=VARCHAR},#{qq,jdbcType=VARCHAR},#{photo,jdbcType=VARCHAR})
    </insert>

SELECT LAST_INSERT_ID()查询生成的id的值,但是需要注意该sql语句必须要与insert的sql语句位于同一次会话中,不然查询不到数据

测试代码

//测试添加用户
	@Test
	public void testAddUser() throws ParseException{
		InputStream inputStream = null;
		try {
			inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		} catch (IOException e) {
			e.printStackTrace();
		}
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		User user = new User();
		user.setUsername("suke");
		user.setAddress("深圳");
		user.setPassword("123");
		user.setSex("男");
		//使用SimpleDateFormat把指定格式的字符串转换为日期
		// 1992-10-12
		SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
		user.setBrithday(fmt.parse("1992-10-12"));
		sqlSession.insert("test.addUser", user);
		
		//提交事务
		sqlSession.commit();
		//关闭SqlSession
		sqlSession.close();
	}

2.10 修改用户

	<!-- 修改用户 -->
	<update id="updateUser" parameterType="org.csmf.mybatis.entity.User">
		update t_user set username=#{username},password=#{password},sex=#{sex},
			brithday=#{brithday},address=#{address} where id=#{id}
	</update>

测试代码:

// 测试修改用户
	@Test
	public void testUpdateUser() throws ParseException {
		InputStream inputStream = null;
		try {
			inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		} catch (IOException e) {
			e.printStackTrace();
		}
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
				.build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		User user = new User();
		user.setId(15);
		user.setUsername("王五");
		user.setAddress("长沙");
		SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
		user.setBrithday(fmt.parse("1991-11-12"));
		user.setPassword("123");
		user.setSex("男");
		//修改
		sqlSession.update("updateUser", user);
		// 提交事务
		sqlSession.commit();

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

3. Mybatis的Dao开发

​ 使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper接口开发方法。

3.1 Mybatis的核心对象

  • SqlSessionFactoryBuilder

    ​ SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是静态代码块中的局部变量

  • SqlSessionFactory

    ​ SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。

  • SqlSession

    1. SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作,默认使用DefaultSqlSession实现类。

    2. SqlSession的实现类即DefaultSqlSession,此对象中对操作数据库实质上用的是Executor

    3. 每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

    4. 打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

3.2 传统的DAO开发模式

​ 程序员需要写dao接口和dao实现类。

​ 需要向dao实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession

步骤:

  1. 编写到接口以及实现类
import java.util.List;

public interface IUserDao {
	/**
	 * 根据ID查询User
	 * @param id  用户Id
	 * @return  用户信息
	 * @throws Exception
	 */
	public User findUserById(int id) throws Exception;
	
	/**
	 * 根据用户的名字模糊查询
	 * @param name 用户的username
	 * @return  一组用户
	 * @throws Exception
	 */
	public List<User> findUserByName(String name) throws Exception;
	
	/**
	 * 添加用户
	 * @param user 用户信息
	 * @return 包含主键的用户
	 * @throws Exception
	 */
	public User addUser(User user) throws Exception;
}


public class UserDaoImpl implements IUserDao {
	//需要往UserDaoImpl注入SQLSessionFactory
	private SqlSessionFactory sqlSessionFactory;
	
	//通过构造方法注入
	public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
		this.sqlSessionFactory = sqlSessionFactory;
	}

	@Override
	public User findUserById(int id) throws Exception {
		/**
		 * 1.得到SqlSession
		 * 2.调用SqlSession对应的方法(selectOne)来操作数据库
		 * 3.关闭SqlSession
		 * 4.返回结果
		 */
		SqlSession sqlSession = sqlSessionFactory.openSession();
		User user = sqlSession.selectOne("test.findUserById", id);
		sqlSession.close();
		return user;
	}

	@Override
	public List<User> findUserByName(String name) throws Exception {
		/**
		 * 1.得到SqlSession
		 * 2.调用SqlSession对应的方法(selectList)来操作数据库
		 * 3.关闭SqlSession
		 * 4.返回结果
		 */
		SqlSession sqlSession = sqlSessionFactory.openSession();
		List<User> users = sqlSession.selectList("test.findUserByName", "%"+name+"%");
		sqlSession.close();
		return users;
	}

	@Override
	public void addUser(User user) throws Exception {
		/**
		 * 1.得到SqlSession
		 * 2.调用SqlSession对应的方法(insert)来操作数据库
		 * 3.提交事务
		 * 4.关闭SqlSession
		 */
		SqlSession sqlSession = sqlSessionFactory.openSession();
		sqlSession.insert("test.addUser", user);
		sqlSession.commit();
		sqlSession.close();
	}
}
  1. 编写SQL映射文件

    <!-- 根据ID查询 -->
    <select id="findUserById" parameterType="int" resultType="org.csmf.mybatis.entity.User">
    		select * from t_user where id = #{id}
    </select>
    <!-- 根据姓名模糊查询 -->
    <select id="findUserByName" parameterType="string" resultType="org.csmf.mybatis.entity.User">
    		select * from t_user where username like #{name}
    </select>
    <!—添加用户-->
    <insert id="addUser" parameterType="org.csmf.mybatis.entity.User">
    		<selectKey order="AFTER" resultType="int" keyProperty="id">
    			select last_insert_id()
    		</selectKey>
    		insert into t_user(username,password,sex,brithday,address) 
    			values(#{username},#{password},#{sex},#{brithday},#{address})
    </insert>
    

总结:

原始Dao开发中存在以下问题:

  • Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法

  • 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护。

3.3 Mapper代理模式

​ Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper接口开发需要遵循以下规范:

  1. 在mapper.xml中namespace写的是对应Mapper接口的全限定名

  1. Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

  2. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
    在这里插入图片描述

实现:

UserMapper.xml:
在这里插入图片描述

UserMapper接口:
在这里插入图片描述

测试代码:

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

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 org.csmf.mybatis.entity.User;
import org.junit.Before;
import org.junit.Test;

/**
 * 测试UserMapper的测试类
 * @author pactera
 *
 */
public class UserMapperTest {
	private SqlSessionFactory sqlSessionFactory;
	@Before
	public void setUp(){
		InputStream inputStream = null;
		try {
			inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		} catch (IOException e) {
			e.printStackTrace();
		}
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}
	@Test
	public  void testFindUserById() throws Exception{
		SqlSession sqlSession = sqlSessionFactory.openSession();
		//创建UserMapper的休息,Mybatis可以自动生成UserMapper接口的代理对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		User user = userMapper.findUserById(2);
		System.out.println(user);
	}
}

总结:

  • selectOne和selectList

动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

  • namespace

mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用包装类或map对象,保证dao的通用性。

  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值