资讯专栏INFORMATION COLUMN

Mybatis学习笔记(一)——基本的CRUD操作

evin2016 / 993人阅读

摘要:将语句硬编码到代码中,修改语句需要重新编译代码设想使用配置文件配置。从结果集中遍历数据的时候存在硬编码。表示一个拼接符号,会引用注入,所以不建议使用。和表示查询出一条记录进行映射。

MyBatis是什么

mybatis是托管在github上的ORM框架,让程序员将主要精力放在SQL上,通过mybatis提供映射方式,自由灵活(SQL的可定制性较高,半自动化)生成满足需求的SQL语句。mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射

在进行项目的编码之前首先初始化数据库,项目所需要的sql脚本。

原生jdbc中的问题总结

观察以下的代码:

@Test
public void testJDBC(){
    final String DB_DRIVER = "org.gjt.mm.mysql.Driver";
    final String DB_URL = "jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf-8";
    final String DB_USER = "root";
    final String DB_PASSWORD = "mysqladmin";
    
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    
    try {
        Class.forName(DB_DRIVER);
        conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
        String sql = "SELECT * FROM user WHERE username = ?";
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, "王五");
        rs = pstmt.executeQuery();
        while (rs.next()) {
            System.out.println("id:" + rs.getInt("id") + ",username:" + rs.getString("username"));
        }
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    } finally {
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( pstmt != null){
            try {
                pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

以上的程序中存在以下的问题:

数据库使用时打开连接,不使用的时候立即释放连接。对数据库进行了频繁的打开和关闭,影响性能(设想:可以使用DBPool)。

将SQL语句硬编码到java代码中,修改SQL语句需要重新编译java代码(设想:使用配置文件配置SQL)。

在向PreparedStatement中设置参数的时候参数的位置和参数值硬编码在代码中(设想:配置文件)。

从结果集中遍历数据的时候存在硬编码。(设想:把结果集映射成javabean)

MyBatis原理

SqlMapConfig.xml:MyBatis全局配置文件(数据源、事务等mybatis运行环境),不是固定名称;

mapper.xml:映射关系(配置SQL语句);

SqlSessionFactory:创建会话(SqlSession);

SqlSession:操作DB(CRUD),面向用户的接口;

Excutor:执行器(SqlSession内部通过执行器操作DB),接口(有2个实现类,基本执行器和缓存执行器);

mappedstatement:底层封装对象(sql语句、输入参数、结果类型)。

入门程序

需求:

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

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

添加用户

更新用户

删除用户

在新建一个源代码目录config,在config目录下使用以下的log4j属性文件(可以从mybatis示例程序中拷贝):

编码前的准备 log4j
# 开发环境中日志的级别使用DEBUG,生产环境中日志级别为ERROR
### 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
工程目录如下所示

在SqlMapConfig.xml中配置MyBatis的运行环境:





    
    
        
            
            
                
            
            
            
                
                
                
                
            
        
    
根据id查询用户信息

1.新建一个pojo名称为User,其字段如下:

private int id;
private String username;
private String sex;
private Date birthday;
private String address;

2.在映射文件(User.xml,这是原始的ibatis映射方式,如果采用mapper代理则名称应该是UserMapper.xml)中配置sql语句。

config/sqlmap目录下新建一个User.xml(输入的参数类型和输出的结果集映射的javabean)内容如下:




    








3.在SqlMapConfig.xml中加载User.xml.(在User.xml的configuration中加入以下内容)


    

4.编写测试类:

/**
 * 根据id查询用户信息
 */
@Test
public void testFindUserById() throws IOException{
    
    // mybatis配置
    String resource = "SqlMapConfig.xml";
    
    // 得到配置文件的流
    InputStream is = Resources.getResourceAsStream(resource);
    
    // 创建会话工厂(传入配置信息)
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
    // 通过会话工厂得到Sqlsession
    SqlSession session = sqlSessionFactory.openSession();
    
    // 查询
    // 参数一:命名空间下的SQL的id;
    // 参数二:和映射文件中匹配的parameterType参数
    // 返回值:映射文件中resultType配置的javabean
    User user = session.selectOne("test.findUserById", 1);
    System.out.println(user);
    
    // 释放资源(关闭会话)
    session.close();
}
根据用户信息模糊查询用户信息

在User.xml中配置如下:


测试类:

/**
 * 模糊查询(可能返回多条)
 */
@Test
public void testFindUserByName() throws IOException {

    // 通过会话工厂得到Sqlsession
    SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession();
    // 返回多条记录
    List users = session.selectList("test.findUserByName", "%明%");
    System.out.println(users);
    session.close();
}

在执行模糊查询的时候我们在编码的时候传入了%作为参数,为了避免出错(少加了%)我们可以在User中配置以下的SQL(同样:我们需要注意:拼接SQL语句可能导致SQL注入):


在测试代码中我们可以这样:

List users = session.selectList("test.findUserByName", "明");

因为${value}进行SQL拼接可能导致sql注入因此不建议使用。

添加用户

在User.xml中配置Statement如下:



    INSERT INTO user(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address});

测试类:

/**
 * 添加用户
 */
@Test
public void testInsertUser() throws IOException{
    
    // 得到sqlsession
    SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession();
    
    // 实例化javabean
    User user = new User();
    user.setUsername("萧晚晴");
    user.setBirthday(new Date());
    user.setSex("2");
    user.setAddress("峨眉山");
    
    // 执行插入语句,并提交事务
    session.insert("test.insertUser",user);
    session.commit();
    
    // 关闭sqlsession
    session.close();
}
自增主键的返回

MySQL自增主键,执行insert提交之前自动生成一个自增主键,通过其LAST_INSERT_ID()函数可以获得其插入后的自增主键。修改以上的插入用户的statement:


    
    
         SELECT  LAST_INSERT_ID();
    
    INSERT INTO user(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address});

这样我们就可以在执行插入之后取得刚刚插入的记录的主键:

/**
 * 添加用户
 */
@Test
public void testInsertUser() throws IOException{
    
    // 得到sqlsession
    SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession();
    
    // 实例化javabean
    User user = new User();
    user.setUsername("萧晚晴");
    user.setBirthday(new Date());
    user.setSex("2");
    user.setAddress("峨眉山");
    
    // 执行插入语句,并提交事务
    session.insert("test.insertUser",user);
    session.commit();
    System.out.println(user.getId());    // 得到插入数据的主键
    // 关闭sqlsession
    session.close();
}
非自增主键的返回

可以使用MySQL的uuid()函数来生成主键,需要修改表的id字段为String,长度设置为35位。执行思路是先通过uuid()查询到主键,将主键输入到SQL中。注意:执行的uuid()函数的顺序相对于INSERT语句之前执行。



     SELECT  UUID();

INSERT INTO user(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address});

如果使用的是Oracle,序列就类似于MySQL的uuid()函数,替换即可:


     SELECT 序列名.nextval();

INSERT INTO user(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address});
删除用户

映射文件:



    DELETE FROM user WHERE id = #{id}

测试类:

/**
 * 根据id删除用户
 */
@Test
public void testDeleteUser() throws IOException{
    // 得到sqlsession
    SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession();
    
    // 执行删除语句,并提交事务
    session.delete("test.deleteUser", 31);
    session.commit();
    // 关闭sqlsession
    session.close();
}
更新用户信息

映射文件



    UPDATE user SET username = #{username},birthday=#{birthday},sex=#{sex},address=#{address} WHERE id = #{id}

测试程序

/**
 * 更新用户
 */
@Test
public void testupdateUser() throws IOException{
    // 得到sqlsession
    SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession();
    
    // 实例化javabean
    User user = new User();
    user.setId(32);
    user.setUsername("上官飞燕");
    user.setBirthday(new Date());
    user.setSex("1");
    user.setAddress("青城山");
    
    // 执行更新语句,并提交事务
    session.update("test.updateUser",user);
    session.commit();
    // 关闭sqlsession
    session.close();
}
总结

parameterType
在映射文件中通过parameterType指定输入参数的类型。

resultType
在映射文件中通过resultType指定输出结果的类型。

#{}和${}

#{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型,pojo、hashmap。如果接收简单类型,#{}中可以写成value或其它名称。
#{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

${}表示一个拼接符号,会引用sql注入,所以不建议使用${}。
${}接收输入参数,类型可以是简单类型,pojo、hashmap。如果接收简单类型,${}中只能写成value。
${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

selectOne和selectList

selectOne表示查询出一条记录进行映射。如果使用selectOne可以实现使用selectList也可以实现(list中只有一个对象)。

selectList表示查询出一个列表(多条记录)进行映射。如果使用selectList查询多条记录,不能使用selectOne。

如果使用selectOne报错:

org.apache.ibatis.exceptions.TooManyResultsException: Expected one
result (or null) to be returned by selectOne(), but found: 4

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64552.html

相关文章

  • Spring Boot学习笔记(六)结合MyBatis实现较为复杂RESTful API

    摘要:前两篇已经构建了标准工程实例,也整合了实现了简单数据库访问,本篇主要更深入的学习下,实现较为完整的数据库的标准服务。到这里,最复杂的数据访问基本就算编写完了。 前两篇已经构建了RESTful API标准工程实例,也整合了MyBatis实现了简单数据库访问,本篇主要更深入的学习下,实现较为完整的数据库CRUD的标准服务。 首先看下要实现的效果吧,完成下面截图部分的API,除了CRUD之外...

    CntChen 评论0 收藏0
  • Java学习路线总结,搬砖工逆袭Java架构师(全网最强)

    摘要:哪吒社区技能树打卡打卡贴函数式接口简介领域优质创作者哪吒公众号作者架构师奋斗者扫描主页左侧二维码,加入群聊,一起学习一起进步欢迎点赞收藏留言前情提要无意间听到领导们的谈话,现在公司的现状是码农太多,但能独立带队的人太少,简而言之,不缺干 ? 哪吒社区Java技能树打卡 【打卡贴 day2...

    Scorpion 评论0 收藏0
  • MyBatis-Plus初步

    摘要:是最流行的关系型数据库管理系统之一,在应用方面,是最好的,关系数据库管理系统应用软件。是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。 本章主要是对MyBatis-Plus的初步介绍,包括一些背景知识、环境搭建、初步使用等知识和例子。对于背景知识,主要包含对MyBatis-Plus的特性介绍、为什么使用MyB...

    娣辩孩 评论0 收藏0
  • Spring Boot学习笔记(七)通用mapper,代码生成,分页组件接入

    摘要:代码自动生成底层服务有很多通用的,利用代码生成最好不过了,这里作者将代码生成放在中的,避免与正式代码冲突。主要通过来实现,项目中的模板文件可以自行定义。相互学习,共同进步 从零开始学习Spring Boot也有几天时间了,项目已经不允许我这么慢慢学习了,急需底层变现实现一套简单的Restful API用于业务支撑。 于是在GitHub上找到了一个不错的demo,直接看demo搭建自己的...

    neroneroffy 评论0 收藏0

发表评论

0条评论

evin2016

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<