MyBatis学习总结(三)MyBatis 的连接池技术/MyBatis 的事务控制/手动提交事务/MyBatis 的动态 SQL 语句/MyBatis 多表查询/一对一、多对一、一对多、多对多查询

一、Java日志(Log4j)的实现(一)Log4j简介Log4j–Log for java(java的日志)Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。(二)Log4j使用步骤1.从...
摘要由CSDN通过智能技术生成

一、MyBatis 的连接池技术分类

  • 连接池就是一个用于存储连接的容器。这个容器其实就是一个集合对象,该集合必须是线程安全的,不能两个线程同时拿到同一个连接。该集合还必须有队列的特性:先进先出(归还的连接放在连接池队列的末尾)。

  • 我们在实际开发中都会使用数据库连接池,因为它可以减少我们获取连接所消耗的时间。

  • 我们在JDBC部分也学习过类似的连接池技术,而在 MyBatis 中也有连接池技术,但是它采用的是自己的连接池技术。在 MyBatis 的核心配置文件中,通过<dataSource type="具体连接池技术">来实现 MyBatis 中连接池的配置。

  • MyBatis核心配置文件中的dataSource标签,type属性就是表示采用何种连接池方式。

  • Mybatis 将它自己的数据源(连接池技术)分为三类(type属性的取值):

    • POOLED:使用传统的 javax.sql.DataSource 规范中的连接池的数据源
    • UNPOOLED:采用传统的获取连接的方式,虽然也实现 javax.sql.DataSource 接口,但不使用连接池的数据源
    • JNDI:采用服务器提供的JNDI技术实现来获取DataSource对象,不同的服务器所能拿到DataSource是不一样的。
      注意:如果不是web或者maven的war工程,是不能使用JNDI的。
      我们如果使用的是Tomcat服务器,那么JNDI采用的连接池就是DBCP连接池。

在这三种数据源中,我们一般采用的是 POOLED 数据源

(一)POOLED

MyBatis核心配置文件:

<!-- 配置数据源(连接池)信息 --> 
<dataSource type="POOLED"> 
	<property name="driver" value="${jdbc.driver}"/>
	<property name="url" value="${jdbc.url}"/>
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</dataSource>
  • MyBatis 在初始化时,根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即:
    type="POOLED":MyBatis 会创建 PooledDataSource 实例
    type="UNPOOLED" : MyBatis 会创建 UnpooledDataSource 实例
    type="JNDI":MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
  • PooledDataSource和UnpooledDataSource都实现了 javax.sql.DataSource 接口。并且PooledDataSource持有一个UnpooledDataSource的引用,当PooledDataSource需要创建 java.sql.Connection 实例对象时,还是通过UnpooledDataSource来创建,PooledDataSource只是提供一种缓存连接池机制。

MyBatis中的DataSource的存取和连接的获取过程:

  • MyBatis 是通过工厂模式来创建数据源 DataSource 对象的,MyBatis 定义了抽象的工厂接口:org.apache.ibatis.datasource.DataSourceFactory,通过其 getDataSource()方法返回数据源DataSource。
  • MyBatis 创建了 DataSource 实例后,会将其放到 Configuration 对象内的 Environment 对象中, 供以后使用。
  • 当我们需要创建 SqlSession 对象并需要执行 SQL 语句时,这时候 MyBatis 才会去调用 dataSource 对象来创建java.sql.Connection对象。也就是说,java.sql.Connection对象的创建一直延迟到执行SQL语句的时候。数据库连接是我们最为宝贵的资源,只有在要用到的时候,才去获取并打开连接,当我们用完了就再立即将数据库连接归还到连接池中。

(二)UNPOOLED

MyBatis核心配置文件:

<!-- 配置数据源(连接池)信息 --> 
<dataSource type="UNPOOLED"> 
	<property name="driver" value="${jdbc.driver}"/>
	<property name="url" value="${jdbc.url}"/>
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</dataSource>

(三)JNDI

JNDI:Java Naming and Directory Interface,Java命名和目录接口。是SUN公司推出的一套规范,属于JavaEE技术之一。目的是模仿windows系统中的注册表在服务器中注册数据源。

创建Maven的war工程并导入依赖:
在这里插入图片描述
在这里插入图片描述
配置自己安装的Maven版本(也可以选择默认的版本):
在这里插入图片描述
导入依赖:

<dependencies>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.5</version>
    </dependency>

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

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

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
    </dependency>

  </dependencies>

在src/main下创建java、resource目录,并标记为对应的目录类型:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
User实体类:

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

public class User implements Serializable {
   

    private Integer userId;
    private String userName;
    private String userAddress;
    private String userSex;
    private Date userBirthday;

    public Integer getUserId() {
   
        return userId;
    }

    public void setUserId(Integer userId) {
   
        this.userId = userId;
    }

    public String getUserName() {
   
        return userName;
    }

    public void setUserName(String userName) {
   
        this.userName = userName;
    }

    public String getUserAddress() {
   
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
   
        this.userAddress = userAddress;
    }

    public String getUserSex() {
   
        return userSex;
    }

    public void setUserSex(String userSex) {
   
        this.userSex = userSex;
    }

    public Date getUserBirthday() {
   
        return userBirthday;
    }

    public void setUserBirthday(Date userBirthday) {
   
        this.userBirthday = userBirthday;
    }

    @Override
    public String toString() {
   
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userAddress='" + userAddress + '\'' +
                ", userSex='" + userSex + '\'' +
                ", userBirthday=" + userBirthday +
                '}';
    }
}

IUserDao:

import com.fox.pojo.User;
import java.util.List;

public interface IUserDao {
   
	//查询所有用户
    List<User> findAll();
}

IUserDao.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="com.fox.dao.IUserDao">
    <!-- 查询所有 -->
    <select id="findAll" resultType="com.fox.pojo.User">
        select * from user;
    </select>
</mapper>

jdbc.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

log4j.properties:

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

在webapp文件下创建META-INF目录,并在META-INF目录中建立一个名为context.xml的配置文件:

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

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <!--
    <Resource
    name="jdbc/test"						        数据源的名称
    type="javax.sql.DataSource"						数据源类型
    auth="Container"								数据源提供者
    maxActive="20"									最大活动数
    maxWait="10000"									最大等待时间
    maxIdle="5"										最大空闲数
    username="root"									用户名
    password="123456"								密码
    driverClassName="com.mysql.jdbc.Driver"			驱动类
    url="jdbc:mysql://localhost:3306/test"	        连接url字符串
    />
     -->
    <Resource
            name="jdbc/test"
            type="javax.sql.DataSource"
            auth="Container"
            maxActive="20"
            maxWait="10000"
            maxIdle="5"
            username="root"
            password="123456"
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/test"
    />
</Context>

配置 MyBatis 核心配置文件SqlMapConfig.xml,数据源写JNDI:

<?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>
    <!-- 配置properties-->
    <properties resource="jdbc.properties"></properties>

    <!--配置环境-->
    <environments default="mysql">
        <!-- 配置mysql的环境-->
        <environment id="mysql">
            <!-- 配置事务 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的必备信息  type属性表示是否使用数据源(连接池)-->
            <dataSource type="JNDI">
                <property name="data_source" value="java:comp/env/jdbc/test"/><!--java:comp/env/是固定的-->
            </dataSource>
        </environment>
    </environments>
    <!-- 配置映射文件的位置 -->
    <mappers>
        <mapper resource="com/fox/dao/IUserDao.xml" />
    </mappers>
</configuration>

配置Tomcat:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在WEB-INF下的index.jsp中写测试代码(因为只有这样才会经过Tomcat服务器 ):

<%@ page import="org.apache.ibatis.io.Resources" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="org.apache.ibatis.session.SqlSessionFactoryBuilder" %>
<%@ page import="org.apache.ibatis.session.SqlSessionFactory" %>
<%@ page import="org.apache.ibatis.session.SqlSession" %>
<%@ page import="com.fox.dao.IUserDao" %>
<%@ page import="com.fox.pojo.User" %>
<%@ page import="java.util.List" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<body>
<h2>Hello World!</h2>
<%
    //1.读取配置文件
    InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
    //2.根据配置文件构建SqlSessionFactory
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(in);
    //3.使用SqlSessionFactory创建SqlSession对象
    SqlSession sqlSession = factory.openSession();
    //4.使用SqlSession构建Dao的代理对象
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    //5.执行dao中的findAll方法
    List<User> users = userDao.findAll();
    for(User user : users){
        System.out.println(user);
    }
    //6.释放资源
    sqlSession.close();
    in.close();
%>
</body>
</html>

运行Tomcat:
在这里插入图片描述
IDEA输出:
在这里插入图片描述

二、MyBatis 的事务控制

在 JDBC 中我们可以通过手动方式将事务的提交改为手动方式,通过 setAutoCommit()方法就可以调整。那么我们的 Mybatis 框架因为是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的setAutoCommit()方法来设置事务提交方式的。
MyBatis是通过sqlsession对象的commit()方法和rollback()方法实现事务的提交和回滚。

(一)MyBatis 中手动提交事务方式

手动提交事务:sqlSession.commit();

我们运行之前所写的代码:

import com.fox.dao.IUserDao;
import com.fox.pojo.User;
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.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;

public class MybatisTest {
   
    private InputStream in = null;
    private SqlSession sqlSession =null;
    private IUserDao userDao = null;

    @Before //标记在非静态方法上。在@Test方法前面执行,而且是在每一个@Test方法前面都执行。
    public void init() throws IOException {
   
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.使用构建者创建工厂对象 SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3.使用 SqlSessionFactory 生产 SqlSession 对象
        sqlSession = factory.openSession();
        //4.使用 SqlSession 创建 dao 接口的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }

    @After //标记在非静态方法上。在@Test方法后面执行,而且是在每一个@Test方法后面都执行。
    public void destroy() throws IOException {
   
        //增删改,记得提交事务
        sqlSession.commit();
        //释放资源
        sqlSession.close();
        in.close();
    }

    @Test
    public void testAddUser(){
   
        User user = new User();
        //由于id是自增的,所以没有id
        user.setUserName("小黑");
        user.setBirthday(new Date());
        user.setUserAddress("上海");
        user.setSex("男");
        userDao.addUser(user);
    }
}

观察在它在控制台输出的结果:
在这里插入图片描述
这是我们的 Connection 的整个变化过程,通过分析我们能够发现之前的 CUD 操作过程中,我们都要手动进行事务的提交,原因是在执行前 setAutoCommit() 方法它的值被设置为 false 了,所以我们在 CUD 操作中,必须通过 sqlSession.commit()方法来执行提交操作。

(二)MyBatis 中自动提交事务方式

通过上面的研究和分析,现在我们一起思考,为什么 CUD 过程中必须使用 sqlSession.commit()提交事务?主要原因就是在连接池中取出的连接,都会将调用 connection.setAutoCommit(false)方法,这样我们就必须使用 sqlSession.commit()方法,相当于使用了 JDBC 中的 connection.commit()方法实现事务提交。
自动提交事务:SqlSession sqlSession = factory.openSession(true);

import com.fox.dao.IUserDao;
import com.fox.pojo.User;
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.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;

public class MybatisTest {
   
    private InputStream in = null;
    private SqlSession sqlSession =null;
    private IUserDao userDao = null;

    @Before //标记在非静态方法上。在@Test方法前面执行,而且是在每一个@Test方法前面都执行。
    public void init() throws IOException {
   
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.使用构建者创建工厂对象 SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        /
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值