mybatis笔记(一)入门程序、dao开发方式、mapper开发方式、全局配置文件、映射文件、动态sql

录:

1、mybatis的介绍
2、分析jdbc的问题
3、mybatis框架原理
4、mybatis入门程序
5、主键策略
6、小结
7、mybatis开发dao的方式--原始dao开发方式
8、mybatis开发dao的方式--Mapper代理的开发方式
9、全局配置文件
10、映射文件--输入参数
11、映射文件--输出结果
12、动态sql
13、mybatis与hibernate的区别及各自应用场景

1、mybatis的介绍    <--返回目录

    * mybatis就是一个封装了jdbc的【持久层框架】,它和hibernate都属于ORM(Object Relational Mapping对象关系映射)框架,
      但是具体来说,hibernate是一个完全的orm框架,而mybatis是一个不完全的orm框架
    * Mybatis让程序员只关注sql本身,而不需要去关注连接的创建、statement的创建等操作。
    * Mybatis会将输入参数、输出结果进行映射。

2、分析jdbc的问题    <--返回目录

  原生态的jdbc代码

public static void main(String[] args) {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    
    try {
        //1、加载数据库驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2、通过驱动管理类获取数据库连接
        connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
        //3、定义sql语句 ?表示占位符
        String sql = "select * from user where username = ?";
        //4、获取预处理statement
        preparedStatement = connection.prepareStatement(sql);
        //5、给sql语句中的?赋值;设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
        preparedStatement.setString(1, "王五");
        //6、向数据库发出sql执行查询,查询出结果集
        resultSet = preparedStatement.executeQuery();
        //7、遍历结果集
        while(resultSet.next()){
            System.out.println(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();
            }
        }
    }
}
View Code

  问题总结
    1)在创建连接时,存在硬编码
          配置文件(全局配置文件)
          2)在执行statement时存在硬编码
          配置文件(映射文件)
          3)频繁的开启和关闭数据库连接,会造成数据库性能下降。
          数据库连接池(全局配置文件)

3、mybatis框架原理    <--返回目录

4、mybatis入门程序    <--返回目录

  选中 config文件夹, 右键-> Build Path -> Use as Source Folder

  

   需求:对订单商品案例中的用户表进行增删改查操作
    1) 根据用户ID查询用户信息--加载load
    2) 根据用户名称模糊查询用户列表--列表展示list,带条件的分页查询
    3) 添加用户
    4) 删除用户
    5) 修改用户

  环境准备
    - Jdk:1.8
    - IDE:eclipse
    - Mybatis:3.2.7
    - 数据库:MySQL 5.X

  下载mybatis: mybaits的代码由github.com管理,下载地址:https://github.com/mybatis/mybatis-3/releases


  sql 脚本

create database db_mybatis_01 default character set utf8;
use db_mybatis_01;
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;

insert  into `user`(`id`,`username`,`birthday`,`sex`,`address`) 
values (1,'王五',NULL,'2',NULL),
(2,'张三','2014-07-10','1','北京市'),
(3,'张小明',NULL,'1','河南郑州'),
(4,'陈小明',NULL,'1','河南郑州'),
(5,'张三丰',NULL,'1','河南郑州'),
(6,'陈小明',NULL,'1','河南郑州'),
(7,'王五',NULL,NULL,NULL);

  导入jar包
    - 核心jar:mybatis-3.2.7.jar
    - 依赖jar:lib目录下,9个
    - mysql 驱动:mysql-connector-java-5.1.40-bin.jar

 

   创建全局配置文件

<?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文件或者声明属性信息 <property name="db.username" value="123" /> -->
    <properties resource="db.properties">
    </properties>

    <!-- <settings></settings> -->

    <!-- 自定义别名 -->
    <typeAliases>
        <!-- 单个别名定义 -->
        <!-- <typeAlias type="com.oy.mybatis.po.User" alias="user"/> -->

        <!-- 批量别名定义(推荐) -->
        <!-- package:指定包名称来为该包下的po类声明别名,默认的别名就是类名(首字母大小写都可) -->
        <!-- <package name="com.oy.mybatis.po" /> -->
    </typeAliases>

    <!-- 配置mybatis的环境信息,与spring整合后,该信息由spring来管理 -->
    <environments default="development">
        <environment id="development">
            <!-- 配置JDBC事务控制,由mybatis进行管理 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源,采用mybatis连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${db.driver}" />
                <property name="url" value="${db.url}" />
                <property name="username" value="${db.username}" />
                <property name="password" value="${db.password}" />
            </dataSource>
        </environment>
    </environments>

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

        <!-- 批量加载映射文件 -->
        <!-- <package name="com.oy.mybatis.mapper" /> -->
    </mappers>
</configuration>

  数据库的配置文件    db.properties

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

  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

  或

log4j.rootLogger=info,appender1,appender2

log4j.appender.appender1=org.apache.log4j.ConsoleAppender 

log4j.appender.appender2=org.apache.log4j.FileAppender 
log4j.appender.appender2.File=d:/logFile.txt
 
log4j.appender.appender1.layout=org.apache.log4j.TTCCLayout
log4j.appender.appender2.layout=org.apache.log4j.TTCCLayout  

  User 实体类

package com.oy.domain;

import java.sql.Date;

public class User {
    private int id;
    private String username; // 用户名
    private Date birthday; // 生日
    private String sex; // 性别
    private String address; // 地址

    // getXxx和setXxx

    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address="
                + address + "]";
    }
}

  映射文件 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:命名空间,对statement的信息进行分类管理 -->
<!-- 注意:在mapper代理时,它具有特殊及重要的作用 -->
<mapper namespace="test">
    <!-- 根据用户ID查询用户信息 -->
    <!-- select:表示一个MappedStatement对象 -->
    <!-- id:statement的唯一标示 -->
    <!-- #{}:表示一个占位符? -->
    <!-- #{id}:里面的id表示输入参数的参数名称,如果该参数是简单类型,那么#{}里面的参数名称可以任意 -->
    <!-- parameterType:输入参数的java类型 -->
    <!-- resultType:输出结果的所映射的java类型(单条结果所对应的java类型) -->
    <select id="findUserById" parameterType="int" resultType="com.oy.domain.User">
        SELECT * FROM USER WHERE id =#{id}
    </select>

    <select id="findUsersByName" parameterType="java.lang.String" resultType="com.oy.domain.User">
        SELECT * FROM USER WHERE username LIKE '%${value}%'
    </select>
    
    <!-- 添加用户 -->
    <!-- selectKey:查询主键,在标签内需要输入查询主键的sql -->
    <!-- order:指定查询主键的sql和insert语句的执行顺序,相当于insert语句来说(表示:什么时候获取主键id,是在insert语句之前,还是之后) -->
    <!-- LAST_INSERT_ID:该函数是mysql的函数,获取自增主键的ID,它必须配合insert语句一起使用 -->
    <insert id="insertUser" parameterType="com.oy.domain.User">
        <selectKey keyProperty="id" resultType="int" order="AFTER">    
            SELECT LAST_INSERT_ID()         
        </selectKey>
    
        INSERT INTO USER(username,birthday,sex,address)
        VALUES(#{username},#{birthday},#{sex},#{address})
    </insert>
    
    <!-- 删除用户 -->
    <delete id="deleteUserById" parameterType="int">
        delete from user where id = #{id}
    </delete>
    
    <!-- 修改用户 -->
    <update id="updateUserById" parameterType="int">
        update user set username = '张小三' where id = #{id}
    </update>
    
    
</mapper>

  测试类

package com.oy.test;

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

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.jupiter.api.Test;

import com.oy.domain.User;

public class Test1 {
    /**
     * 按id查询用户
     * @throws Exception
     */
    @Test
    public void findUserByIdTest() throws Exception {
        //读取配置文件
        //全局配置文件的路径
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
        //调用SqlSession的增删改查方法
        //第一个参数:表示statement的唯一标示
        User user = sqlSession.selectOne("test.findUserById", 1);
        System.out.println(user);
        
        //关闭资源
        sqlSession.close();
    }
    
    /**
     * 按username查询用户
     * @throws Exception
     */
    @Test
    public void findUsersByNameTest() throws Exception{
        //读取配置文件
        //全局配置文件的路径
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
        //调用SqlSession的增删改查方法
        //第一个参数:表示statement的唯一标示
        List<User> list = sqlSession.selectList("test.findUsersByName", "小明");
        for(User user:list){
            System.out.println(user);
        }
        //关闭资源
        sqlSession.close();
    }
    
    /**
     * 添加用户
     * @throws Exception
     */
    @Test
    public void insertUserTest() throws Exception{
        //读取配置文件
        //全局配置文件的路径
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
        User user = new User();
        user.setUsername("东哥hm19");
        user.setAddress("宝盛西里24号楼");
        
        //调用SqlSession的增删改查方法
        //第一个参数:表示statement的唯一标示
        sqlSession.insert("test.insertUser", user);
        
        int id = user.getId();
        //System.out.println(user.getId());
        User user2 = sqlSession.selectOne("test.findUserById", id);
        System.out.println(user2);
        
        //提交事务
        sqlSession.commit();
        //关闭资源
        sqlSession.close();
    }
    
    /**
     * 删除用户
     * @throws Exception
     */
    @Test
    public void deleteUserByIdTest() throws Exception{
        //读取配置文件
        //全局配置文件的路径
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
        //调用SqlSession的增删改查方法
        //第一个参数:表示statement的唯一标示
        //先查询要删除的user,然后删除
        User user = sqlSession.selectOne("test.findUserById", 28);
        System.out.println(user);
        sqlSession.delete("test.deleteUserById", 28);
        
        //提交事务
        sqlSession.commit();
        //关闭资源
        sqlSession.close();
    }
    
    /**
     * 按id修改用户
     * @throws Exception
     */
    @Test
    public void updateUserByIdTest() throws Exception{
        //读取配置文件
        //全局配置文件的路径
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
        //调用SqlSession的增删改查方法
        //第一个参数:表示statement的唯一标示
        User user = sqlSession.selectOne("test.findUserById", 10);
        System.out.println(user);
        sqlSession.update("test.updateUserById", 10);
        User user2 = sqlSession.selectOne("test.findUserById", 10);
        System.out.println(user2);
        
        //提交事务
        sqlSession.commit();
        //关闭资源
        sqlSession.close();
    }
}

5、主键策略    <--返回目录

  主键策略为自增时的执行顺序为:order="AFTER"   

INSERT  INTO `user`(`username`,`birthday`,`sex`,`address`) VALUES ('王五',NULL,'2',NULL);
SELECT LAST_INSERT_ID();       //在insert语句执行完后,获取id。即获取上面记录的id

  主键策略为:uuid

<!-- 主键策略为:UUID -->
<insert id="insertUser2" parameterType="com.oy.domain.User">
    <selectKey keyProperty="id" resultType="string" order="BEFORE">
        SELECT UUID() 
    </selectKey>

    INSERT INTO USER
    (id,username,birthday,sex,address)
    VALUES(#{id},#{username},#{birthday},#{sex},#{address})
</insert>

  主键策略为uuid时的执行顺序为:order="BEFORE"   

SELECT UUID();
INSERT INTO USER(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address});

  主键返回值序列:序列也就是sequence,它是Oracle的主键生成策略

<!-- 主键之sequence -->
<insert id="insertUser3" parameterType="com.oy.domain.User">
    <selectKey keyProperty="id" resultType="int" order="BEFORE">
        SELECT seq.nextval FROM dual
    </selectKey>

    INSERT INTO USER
    (id,username,birthday,sex,address)
    VALUES(#{id},#{username},#{birthday},#{sex},#{address})
</insert>        

 

6、小结     <--返回目录

    * #{}和${}
        #{}表示占位符?,#{}接收简单类型的参数时,里面的名称可以任意
        ${}表示拼接符,${}接收简单类型的参数时,里面的名称必须是value
        ${}里面的值会原样输出,不加解析(如果该参数值是字符串,也不会添加引号)
        ${}存在sql注入的风险,但是有些场景下必须使用,比如排序后面会动态传入排序的列名
                
    * parameterType和resultType
        parameterType指定输入参数的java类型,parameterType只有一个,也就是说入参只有一个。
        resultType指定输出结果的java类型(是单条记录的java类型)
        
    * selectOne和selectList
        selectOne查询单个对象
        selectList查询集合对象

7、mybatis开发dao的方式--原始dao开发方式    <--返回目录

  原始dao开发方式:开发dao接口和dao实现类,由ibatis遗留下来的风格

   dao接口和实现类

public interface UserDao {
    public User findUserById(int id);
    public List<User> findUsersByName(String name);
    public void insertUser(User user);
    public void deleteUserById(int id);
    public void updateUserById(int id);
}

public class UserDaoImpl implements UserDao {
    
    private SqlSessionFactory sqlSessionFactory;
    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    /**
     * 按id查询用户
     */
    @Override
    public User findUserById(int id) {
        // 创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        User user = sqlSession.selectOne("test.findUserById", id);
        // 关闭资源
        sqlSession.close();
        return user;
    }

    /**
     * 按username查询用户
     */
    @Override
    public List<User> findUsersByName(String name) {
        // 创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        List<User> userList = sqlSession.selectList("test.findUserByName", name);
        return userList;
    }

    /**
     * 添加用户
     */
    @Override
    public void insertUser(User user) {
        // 创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        sqlSession.insert("test.insertUser", user);
    }

    /**
     * 按id删除用户
     */
    @Override
    public void deleteUserById(int id) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.update("test.deleteUserById", id);
    }

    /**
     * 按id修改用户
     */
    @Override
    public void updateUserById(int id) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.update("test.updateUserById", id);
    }

}

  其他与上一项目一致。

  测试类

package com.oy.test;

import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import com.oy.dao.UserDao;
import com.oy.dao.UserDaoImpl;
import com.oy.domain.User;

public class Test1 {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void setUp() throws Exception {
        // 读取配置文件
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 创建SqlSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testFindUserById() throws Exception {
        // 创建UserDao
        UserDao dao = new UserDaoImpl(sqlSessionFactory);//注入sqlSessionFactory
        
        User user = dao.findUserById(1);
        System.out.println(user);
    }

}

8、mybatis开发dao的方式--Mapper代理的开发方式    <--返回目录

  Mapper代理使用的是jdk的代理策略。
  Mapper代理的开发规范
    1)mapper接口的全限定名要和mapper映射文件的namespace值一致。
    2)mapper接口的方法名称要和mapper映射文件的statement的id一致。
    3)mapper接口的方法参数类型要和mapper映射文件的statement的parameterType(输入参数类型)的值一致,
     而且它的参数是一个。
    4)mapper接口的方法返回值类型要和mapper映射文件的statement的resultType(返回结果类型)的值一致。

  创建接口 com.oy.mapper.UserMapper   

public interface UserMapper{
    public User findUserById(int id) throws Exception;   //int id为输入参数   User为输出结果
}    

  mapper映射文件:在config(源目录,也就是src)下创建mapper目录然后创建UserMapper.xml(这是mybatis的命名规范,当然,也不是必须是这个名称)

<mapper namespace="com.oy.mapper.UserMapper">  // namespace="com.oy.mapper.UserMapper"与接口全限定名称相同
    <select id="findUserById" parameterType="int" resultType="com.oy.domain.User">   //id="findUserById"与接口方法名称相同
        SELECT * FROM USER WHERE id = #{id}
    </select>
</mapper>

  SqlMapConfig.xml加载映射文件

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

  测试代码‘

private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {        
    String resource = "SqlMapConfig.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);    
    sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
    // 创建UserMapper对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.findUserById(1);
    System.out.println(user);
    sqlSession.close();
}

9、全局配置文件    <--返回目录

  SqlMapConfig.xml的配置内容和顺序如下(顺序不能乱):

Properties(属性)
Settings(全局参数设置)
【typeAliases】(类型别名)SSM整合后依然会用到
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境信息集合)
    environment(单个环境信息)
        transactionManager(事物)
        dataSource(数据源)
mappers(映射器)

  property加载的顺序

1)先加载properties中property标签声明的属性
2)再加载properties标签引入的properties配置文件中的属性,如果同名,后面会覆盖前面的值
3)parameterType的值会和properties的属性值发生冲突,如果发现上面已经有同名的属性了,那后面会覆盖前面的值

  mybatis支持的别名

别名    映射的类型
_byte     byte 
_long     long 
_short     short 
_int     int 
_integer     int 
_double     double 
_float     float 
_boolean     boolean 
string     String    java.lang.String
byte     Byte 
long     Long 
short     Short 
【int     Integer】 
integer     Integer 
double     Double 
float     Float 
boolean     Boolean 
date     Date 
decimal     BigDecimal 
bigdecimal     BigDecimal 

  自定义别名   

<typeAliases>
    <typeAlias type="com.oy.domain.User" alias="user"/>
    <package:指定包名称来为该包下的po类声明别名,默认的别名就是类名(首字母大小写都可)
    <package name="com.oy.domain"/>
</typeAliases>        

  在SqlMapConfig.xml文件中加载映射文件

<mapper resource="sqlmap/User.xml" />   相对于类路径src
<mapper url="file:///D:workspace_spingmvcmybatis_01configsqlmapUser.xml" />    使用完全限定路径
<mapper class="cn.itcast.mapper.UserMapper"/>注意:此种方法要求mapper接口和mapper映射文件要名称相同,且放到同一个目录下;
【<package name="cn.itcast.mapper"/>注意:此种方法要求mapper接口和mapper映射文件要名称相同,且放到同一个目录下;】
<!-- 加载映射文件 -->
<mappers>
    <mapper resource="User.xml" />  相对类路径src
    <!-- <mapper resource="mapper/UserMapper.xml" /> -->

    <!-- 批量加载映射文件,推荐使用该种方式 -->
    <package name="com.oy.mapper" />
</mappers>    

10、映射文件--输入参数    <--返回目录

  parameterType="int等简单类型|pojo类型|包装pojo类型|Map类型"   

  parameterType="Map类型"

<!-- 传递hashmap综合查询用户信息 -->
<select id="findUserByHashmap" parameterType="hashmap" resultType="user">
   select * from user where id=#{id} or username like '%${username}%'   //id和username是hashmap的key。
</select>

  测试

Public void testFindUserByHashmap()throws Exception{
    //获取session
    SqlSession session = sqlSessionFactory.openSession();
    //获限mapper接口实例
    UserMapper userMapper = session.getMapper(UserMapper.class);
    //构造查询条件Hashmap对象
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("id", 1);
    map.put("username", "小明");
    
    //传递Hashmap对象查询用户列表
    List<User>list = userMapper.findUserByHashmap(map);
    //关闭session
    session.close();
}

  异常测试:传递的map中的key和sql中解析的key不一致。测试结果没有报错,只是通过key获取值为空。

11、映射文件--输出结果    <--返回目录

  resultType="int等简单类型|pojo类型"

  resultType的使用要求:

  - 使用resultType进行结果映射时,需要查询出的列名和映射的对象的属性名一致,才能映射成功。
  - 如果查询的列名和对象的属性名全部不一致,那么映射的对象为空。
  - 如果查询的列名和对象的属性名有一个一致,那么映射的对象不为空,但是只有映射正确那一个属性才有值。
  - 如果查询的sql语句中的列名有别名,那么这个别名就代表列名,别名需要与映射的对象的属性名一致。所以,假如数据库中user表的列名为uid,但是领域对象User的属性为id,在查询时可以指定uid的别名为id

  resultMap的使用要求:使用resultMap进行结果映射时,不需要查询的列名和映射的属性名必须一致。

  但是需要声明一个resultMap,来对列名和属性名进行映射。            
        - 需求:对以下sql查询的结果集进行对象映射 Select id id_,username username_,sex sex_ from user where id = 1;
        - 映射文件

<resultMap type="user" id="UserRstMap">    //注意type="user",mapper接口中findUserRstMap()方法返回值为User对象
    <id column="id_" property="id"/>   
    <result column="username_" property="username"/>
    <result column="sex_" property="sex"/>
</resultMap>
<select id="findUserRstMap" parameterType="int" resultMap="UserRstMap">
    Select id id_,username username_,sex sex_ from user where id = #{id};
</select>

12、动态sql    <--返回目录

  在mybatis中,它提供了一些动态sql标签,可以让程序员更快得进行mybatis开发,这些动态sql可以提高sql的可重用性。
  常用的动态sql标签:if标签、where标签、sql片段、foreach标签。

  if标签/where标签

    - 需求:综合查询时,查询条件由用户来输入,用户名称可以为空,需要满足这种情况下的sql编写。
    - 映射文件

<select id="findUserList" parameterType="com.oy.po.UserQueryVO" resultType="user">  //注明:UserQueryVO是个包装pojo类,
    SELECT * FORM user                                                                //封装了private User user;
    <where>   //<where>的作用:拼接条件,并去除多余的的AND
        <if test="user != null">   //判断当输入参数为空时,做不同处理
            <if test="user.username != null and user.username != ''">
                AND username LIKE '%${user.username}%'
            </if>
            <if test="user.sex != null and user.sex != ''">
                AND sex=#{user.sex}
            </if>
        </if>
    </where>
</select>

  sql片段

  - sql片段可以让代码有更高的可重用性
        - sql片段需要先定义后使用
        - 定义sql片段:

<!--定义sql片段
    sql片段内,可以定义sql语句的任何部分
    sql片段内,最好不要将where和select关键字声明在内
-->
<sql id="whereClause">
    <if test="user != null">
        <if test="user.username != null and user.username != ''">
            AND username LIKE '%${user.username}%'
        </if>
        <if test="user.sex != null and user.sex != ''">
            AND sex=#{user.sex}
        </if>
    </if>
</sql>

  - 使用sql片段:

<select id="findUserList" parameterType="com.oy.po.UserQueryVO" resultType="user">  
    SELECT * FORM user                                                                    
    <where>   
        <!--引入sql片段-->    
        <include refid="whereClause"/>    
    </where>
</select>

  

  foreach标签

  - 可以循环传入参数
        - 需求:综合查询时,会根据用户ID集合进行查询 SELECT * FROM USER WHERE id IN (1,2,10)
        - 修改包装pojo类
          public class UserQueryVO{
            private User user;
            private List<Integer> idList;//商品id集合
          }
        - 映射文件

<select id="findUserList" parameterType="com.oy.po.UserQueryVO" resultType="user">
    SELECT * FROM USER 
    <where>
        <if test="idLIst != null">
            AND id IN
            <foreach collection="idList" item="id" open="(" close=")" separator=",">
                #{id}
            </foreach>
        </if>
    </where>                
</select>        

  - 测试代码

List<Integet> idList = new ArrayList<Integer>();
idList.add(1);
idList.add(2);
idList.add(10);
VO.setIdList(idList);
List<User> list = mapper.findUsreList(VO);

  - 最后发送的sql语句为:SELECT * FROM USER WHERE id IN (?,?,?)

13、mybatis与hibernate的区别及各自应用场景    <--返回目录

    * Mybatis技术特点:
        1)通过直接编写SQL语句,可以直接对SQL进行性能的优化;
        2)学习门槛低,学习成本低。只要有SQL基础,就可以学习mybatis,而且很容易上手;
        3)由于直接编写SQL语句,所以灵活多变,代码维护性更好。
        4)不能支持数据库无关性,即数据库发生变更,要写多套代码进行支持,移植性不好。
        
    * Hibernate技术特点:
        1)标准的orm框架,程序员不需要编写SQL语句。
        2)具有良好的数据库无关性,即数据库发生变化的话,代码无需再次编写。
        3)学习门槛高,需要对数据关系模型有良好的基础,而且在设置ORM映射的时候,需要考虑好性能和对象模型的权衡。
        4)程序员不能自主的去进行SQL性能优化。
        
    * Mybatis应用场景:
        需求多变的互联网项目,例如电商项目。
    * Hibernate应用场景:
        需求明确、业务固定的项目,例如OA项目、ERP项目等。

---

原文地址:https://www.cnblogs.com/xy-ouyang/p/13762548.html