Mybatis学习笔记一

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis学习笔记一相关的知识,希望对你有一定的参考价值。

Mybatis介绍

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

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

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

使用jdbc编程问题总结

  1.  数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。
  2. Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。
  3. 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
  4. 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

Mybatis架构

1、mybatis配置:

  • SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
  • mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

2、通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

4、mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

5、Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。

6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

Mybatis入门程序

 1、pom.xml如下:

<?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.yyb</groupId>
    <artifactId>mybitis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.7</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.8</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>mybatis</finalName>
        <!--配置jdk版本为1.8-->
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2、创建数据库,准备数据。

/*
Navicat MySQL Data Transfer

Source Server         : localhost_3306
Source Server Version : 50521
Source Host           : localhost:3306
Source Database       : mybatis

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

Date: 2015-04-09 16:03:53
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- 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`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES (\'3\', \'1\', \'1000010\', \'2015-02-04 13:22:35\', null);
INSERT INTO `orders` VALUES (\'4\', \'1\', \'1000011\', \'2015-02-03 13:22:41\', null);
INSERT INTO `orders` VALUES (\'5\', \'10\', \'1000012\', \'2015-02-12 16:13:23\', 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=27 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (\'1\', \'王五\', null, \'2\', null);
INSERT INTO `user` VALUES (\'10\', \'张三\', \'2014-07-10\', \'1\', \'北京市\');
INSERT INTO `user` VALUES (\'16\', \'张小明\', null, \'1\', \'河南郑州\');
INSERT INTO `user` VALUES (\'22\', \'陈小明\', null, \'1\', \'河南郑州\');
INSERT INTO `user` VALUES (\'24\', \'张三丰\', null, \'1\', \'河南郑州\');
INSERT INTO `user` VALUES (\'25\', \'陈小明\', null, \'1\', \'河南郑州\');
INSERT INTO `user` VALUES (\'26\', \'王五\', null, null, null);
创建表SQL语句

3、创建pojo

package cn.itcast.mybatis.po;

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

public class Orders  implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private Integer id;

    private Integer userId;

    private String number;

    private Date createtime;

    private String note;

    public Integer getId() {
        return id;
    }

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

    public Integer getUserId() {
        return userId;
    }

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

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number == null ? null : number.trim();
    }

    public Date getCreatetime() {
        return createtime;
    }

    public void setCreatetime(Date createtime) {
        this.createtime = createtime;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note == null ? null : note.trim();
    }

    
    
}
Orders.java
package cn.itcast.mybatis.po;

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

public class User implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private Integer id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址


    public Integer getId() {
        return id;
    }
    public void setId(Integer 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 + "]";
    }

    
    

}
User.java

4、在resources下加入log4j.propertiesSqlMapConfig.xml配置文件

mybatis默认使用log4j作为输出日志信息。log4j.properties配置如下:

# 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
View Code

SqlMapConfig.xmlmybatis核心配置文件,配置文件内容为数据源、事务管理。配置如下:

<?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 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/mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
</configuration>

5、在resources下创建一个mapper文件夹,添加User.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="test">
    <!-- id:statement的id 或者叫做sql的id-->
    <!-- parameterType:声明输入参数的类型 -->
    <!-- resultType:声明输出结果的类型,应该填写pojo的全路径 -->
    <!-- #{}:输入参数的占位符,相当于jdbc的? -->
    <select id="queryUserById" parameterType="int"  resultType="com.yyb.pojo.User">
        SELECT * FROM user WHERE id  = #{id}
    </select>
</mapper>

6、添加测试类

package com.yyb.test;
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;


/**
 * Created by Administrator on 2017/8/15.
 */
public class Test {
    @org.junit.Test
    public void func1() {
        String path = "SqlMapConfig.xml";
        InputStream resourceAsStream = null;
        try {
            // 1. 加载SqlMapConfig.xml配置文件
            resourceAsStream = Resources.getResourceAsStream(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 2. 创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3. 创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 4. 执行SqlSession对象执行查询,获取结果User
        // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
        Object user = sqlSession.selectOne("test.queryUserById", 1);

        // 5. 打印结果
        System.out.println(user);

        // 6. 释放资源
        sqlSession.close();
    }
}

最终项目结构如下:

7、测试效果:User [id=1, username=王五, sex=2, birthday=null, address=null]

实现根据用户名模糊查询用户

 在user.xml中添加以下代码:

<!-- //根据用户名称模糊查询用户列表
    #{}    select * from user where id = ?    占位符  ? ==  \'五\'
    ${}    select * from user where username like \'%五%\'  字符串拼接
     区别主要是单引号的问题  #{}会加单引号  ${value}不会加单引号,名字必须为value
     -->
    <select id="findByUserName" parameterType="String" resultType="com.yyb.pojo.User">
        SELECT * FROM user WHERE username  like \'%${value}%\'
--也可以这样,防止SQL注入:
SELECT * FROM user WHERE username like "%"#{value}"%"
    </select>

测试代码如下:

    @org.junit.Test
    public void func2() {
        String path = "SqlMapConfig.xml";
        InputStream resourceAsStream = null;
        try {
            // 1. 加载SqlMapConfig.xml配置文件
            resourceAsStream = Resources.getResourceAsStream(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 2. 创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3. 创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 4. 执行SqlSession对象执行查询,获取结果User
        // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
        List<User> users = sqlSession.selectList("test.findByUserName", "五");

        // 5. 打印结果
        System.out.println(users);

        // 6. 释放资源
        sqlSession.close();
    }

#{}${}的区别

#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

parameterType和resultType

parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。

resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中

selectOne和selectList

selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:

org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)

selectList可以查询一条或多条记录。

实现添加用户

 在user.xml中添加如下代码:

 <insert id="addUser" parameterType="com.yyb.pojo.User" >
      INSERT into USER(username,birthday,address,sex) VALUES (#{username},#{birthday},#{address},#{sex})
    </insert>

测试代码如下;

 @org.junit.Test
    public void func3() {
        String path = "SqlMapConfig.xml";
        InputStream resourceAsStream = null;
        try {
            // 1. 加载SqlMapConfig.xml配置文件
            resourceAsStream = Resources.getResourceAsStream(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 2. 创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3. 创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 4. 执行SqlSession对象执行查询,获取结果User
        // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
        User user=new  User();
        user.setUsername("yyb");
        user.setSex("男");
        user.setBirthday(new Date());
        user.setAddress("cd");
       以上是关于Mybatis学习笔记一的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记——Mybatis逆向工程MBG;MyBatis逆向工程MBG使用步骤

MyBatis-05-笔记

mybatis学习(39):动态sql片段

译丨Yarn - Javascript 新一代套件管理

MyBatis学习笔记11:解决字段名和属性的映射关系

Mybatis学习笔记导航