热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

MyBatis实践--Mapper与DAO_MySQL

MyBatis实践标签:Java与存储MyBatis简介MyBatis前身是iBatis,是一个基于Java的数据持久层对象关系映射(ORM)框架MyBatis是对JDBC的封装,使开发人员只需关注SQL本身,而不需花费过多的精力去

MyBatis简介

MyBatis前身是iBatis,是一个基于Java的数据持久层/对象关系映射(ORM)框架.
\
MyBatis是对JDBC的封装,使开发人员只需关注SQL本身,而不需花费过多的精力去处理如注册驱动设置参数创建Connection/Statement解析结果集等JDBC过程性代码.MyBatis基于XML/注解的方式配置Statement,执行SQL,并将执行结果映射成Java对象, 大大降低了数据库开发的难度.

MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. MyBatis eliminates almost all of the JDBC code and manual setting of parameters and retrieval of results. MyBatis can use simple XML or Annotations for configuration and map primitives, Map interfaces and Java POJOs (Plain Old Java Objects) to database records.
– MyBatis项目地址/在线文档.


初识MyBatis

使用MyBatis需要在pom.xml中添加如下依赖:


    org.mybatis
    mybatis
    3.3.0


    mysql
    mysql-connector-java
    5.1.36

Select

配置mybatis/mybatis-configuration.xml
作为MyBatis的全局配置文件,其配置了MyBatis的运行环境信息(如数据源/mapper文件等).




    
        
            
            
            
            
                
                
                
                
            
        
    

    
    
        
    
书写UserDAO(mapper映射)
最为MyBatis最核心的部分,配置了操作数据库的SQL语句:




    

    

属性 描述
namespace 命名空间,用于隔离SQL语句
parameterType 定义SQL输入映射类型,MyBatis通过OGNL从输入对象中获取参数传入SQL语句.
resultType 定义SQL输出映射类型,MyBatis将SQL查询结果的一行记录映射为resultType指定的类型.

mapper映射文件名有UserDAO.xml/UserMapper.xml/User.xml等几种形式, 其一般存放在与mybatis-configuration.xml同级的mapper目录下,由于其主要作用为定义SQL语句与映射关系, 因此一般统称为mapper映射文件.

定义PO类
PO类主要作用为SQL(输入/输出)映射,通常与数据库表对应:
/**
 * @author jifang
 * @since 15/12/31 下午2:27.
 */
public class User {

    private Integer id;

    private String name;

    private String password;

    public User() {
    }

    public User(Integer id, String name, String password) {
        this.id = id;
        this.name = name;
        this.password = password;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
UserDAO(Java对象)
获得SqlSession,执行SQL语句, 得到映射结果:
/**
 * @author jifang
 * @since 16/2/24 下午6:15.
 */
public class UserDAO {

    private SqlSessionFactory factory;

    @Before
    public void setUp() throws IOException {
        String resource = "mybatis/mybatis-configuration.xml";
        factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(resource));
    }

    @Test
    public void selectUserById() {
        try (SqlSession session = factory.openSession()) {
            User user = session.selectOne("namespace.selectUserById", 1);
            System.out.println(user);
        }
    }

    @Test
    public void selectUserByName() {
        try (SqlSession session = factory.openSession()) {
            List users = session.selectList("namespace.selectUserByName", "student");
            for (User user : users) {
                System.out.println(user);
            }
        }
    }
}

Insert

mapper

    INSERT INTO user(name, password) VALUES(#{name}, #{password});
UserDAO
@Test
public void insertUser() {
    try (SqlSession session = factory.openSession()) {
        User user = new User();
        user.setName("new_name1");
        user.setPassword("new_password");
        session.insert("namespace.insertUser", user);
        session.commit();
    }
}

自增主键返回

修改mapper文件,添加,可以将MySQL的自增主键(即刚刚插入数据时生成的ID)返回:


    
        SELECT LAST_INSERT_ID();
    
    INSERT INTO user(name, password) VALUES(#{name}, #{password});
属性 描述
keyProperty 指定存储到DO中的哪个属性;
order selectKey执行顺序(相对于insert语句),AFTER/BEFORE;
resultType 主键返回类型(DO中对应属性的类型);
LAST_INSERT_ID() MySQL函数,返回auto_increment自增列新记录值.
UserDAO
@Test
public void insertUser() {
    try (SqlSession session = factory.openSession()) {
        System.out.println(session);
        User user = new User(null, "new_name", "new_password");
        session.insert("namespace.insertUser", user);
        // 需要在commit之后才能获得自增主键
        session.commit();
        System.out.println(user.getId());
    }
}

该功能还可以通过的useGeneratedKeys/keyProperty两个属性合作完成, 详见MyBatis文档.


Update

mapper

    UPDATE user SET name = #{name}, password = #{password} WHERE id = #{id};
UserDAO
@Test
public void updateUserById() {
    try (SqlSession session = factory.openSession(true)) {
        session.update("namespace.updateUserById",
                new User(1, "feiqing", "ICy5YqxZB1uWSwcVLSNLcA=="));
    }
}

Delete

mapper

    DELETE FROM user WHERE id = #{id};
UserDAO
@Test
public void deleteUserById() {
    try (SqlSession session = factory.openSession(true)) {
        session.delete("namespace.deleteUserById", 51615);
    }
}

小结

#{}/${}

#{}: 表示一个占位符号,实现向PreparedStatement占位符中设置值(#{}表示一个占位符?),自动进行Java类型到JDBC类型的转换(因此#{}可以有效防止SQL注入).#{}可以接收简单类型或PO属性值,如果parameterType传输的是单个简单类型值,#{}花括号中可以是value或其它名称. ${}: 表示拼接SQL串,通过${}可将parameterType内容拼接在SQL中而不进行JDBC类型转换,${}可以接收简单类型或PO属性值,如果parameterType传输的是单个简单类型值,${}花括号中只能是value.
虽然${}不能防止SQL注入,但有时${}会非常方便(如order by排序,需要将列名通过参数传入SQL,则用ORDER BY ${column},使用#{}则无法实现此功能(详见JDBC基础关于PreparedStatement的讨论).

SqlSession
提供操作数据库的方法(如:selectOne/selectList).但SqlSession是线程不安全的,因此最好将其定义成局部变量使用.

MyBatis优点(与JDBC相比)
SQL写在Java代码中导致不易维护, 而MyBatis将SQL写在mapper中,XML与Java代码分离. 向SQL语句传参繁琐(如:SQL的where条件不一,SQL数据类型与Java不同),MyBatis通过parameterType自动将Java对象映射至SQL语句. 结果集解析麻烦(SQL变化导致解析代码变化,SQL数据类型与Java不同),MyBatis通过resultType自动将SQL执行结果映射成Java对象.

附: 最好在pom.xml中添加一个日志系统实现(logback/log4j), 这样会在调试程序时打印日志信息,便于查错, 以logback为例:

pom.xml

    ch.qos.logback
    logback-classic
    1.1.2
logback.xml


    
    

    
        
            ${pattern}
        
    
    
        
            ${logRoot}/common-server.%d{yyyy-MM-dd}.log
            7
        
        
            ${pattern}
        
    

    
        
        
    

其他关于MyBatis日志的详细信息可参考MyBatis文档日志部分.


DAO开发

使用MyBatis开发DAO有两个方法,原始DAO开发Mapper映射DAO开发.


原始DAO开发

原始DAO开发需要开发人员编写DAO接口DAO实现,如根据ID查询用户信息:

mapper(同前)
UserDAO接口
/**
 * @author jifang
 * @since 16/2/22 上午10:20.
 */
public interface UserDAO {
    User selectUserById(Integer id) throws Exception;
}
UserDAO实现
public class UserDAOImpl implements UserDAO {

    private SqlSessionFactory factory;

    public UserDAOImpl(SqlSessionFactory factory) {
        this.factory = factory;
    }

    @Override
    public User selectUserById(Integer id) throws Exception {
        SqlSession session = factory.openSession();
        User user = session.selectOne("namespace.selectUserById", id);
        session.close();
        return user;
    }
}
Client
public class MyBatisClient {

    @Test
    public void originalClient() throws Exception {
        UserDAO dao = new UserDAOImpl(new SqlSessionFactoryBuilder().
                build(ClassLoader.getSystemResourceAsStream("mybatis/mybatis-configuration.xml")));
        User user = dao.selectUserById(1);
        System.out.println(user);
    }
}
原始DAO开发中存在的问题:
1) DAO实现方法体中存在很多过程性代码.
2) 调用SqlSession的方法(select/insert/update)需要指定Statement的id,存在硬编码,不利于代码维护.

Mapper映射开发

mapper映射开发方法只需编写DAO接口,MyBatis根据接口定义与mapper文件中的SQL语句动态创建接口实现.

mapper



    

注意: 此时namespace必须与UserDAO接口的全限定名相同.

UserDAO接口与前面相同, 但不再使用UserDAOImpl Client
/**
 * @author jifang
 * @since 16/2/22 下午2:57.
 */
public class MyBatisClient {

    private SqlSession session;

    private SqlSessionFactory factory;

    @Before
    public void setUp() {
        factory = new SqlSessionFactoryBuilder().
                build(ClassLoader.getSystemResourceAsStream("mybatis/mybatis-configuration.xml"));
        session = factory.openSession();
    }

    @Test
    public void mapperClient() throws Exception {
        UserDAO dao = session.getMapper(UserDAO.class);
        User user = dao.selectUserById(1);
        System.out.println(user);
    }

    @After
    public void tearDown() {
        session.close();
    }
}
mapper映射开发方法需要遵循以下规范:
mapper文件中的namespace与DAO接口的全限定名相同; mapper文件中的Statement的id与DAO接口方法名相同; mapper文件中的Statement的parameterType/resultType与DAO方法的入参/回参类型相同.

Mapper映射

mapper映射文件(如UserDAO.xml)主要作用是定义SQL语句(每个SQL是一个Statement),是MyBatis的核心.

MyBatis官方推荐使用mapper映射的方法来开发DAO,因此我们以后就不再过多介绍原始DAO的开发.


输入映射

多个形参

传递简单类型前面示例已经使用过,在此就不再赘述.当需要传递多个形参时,不再需要设置parameterType参数:

mapper

    UPDATE user SET name = #{1}, password = #{2} WHERE id = #{0};
UserDAO
void updateUserById(Integer id, String name, String password) throws Exception;

传入PO

MyBatis使用OGNL表达式解析对象属性值:

mapper
UserDAO
User selectUserByNamePassword(User user) throws Exception;

传入Map

mapper

#{}花括号内对应Map的key.

UserDAO
User selectUserByMap(Map map) throws Exception;

输出映射

输出简单类型

推荐阅读
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 使用C#开发SQL Server存储过程的指南
    本文介绍如何利用C#在SQL Server中创建存储过程,涵盖背景、步骤和应用场景,旨在帮助开发者更好地理解和应用这一技术。 ... [详细]
  • MySQL 数据库迁移指南:从本地到远程及磁盘间迁移
    本文详细介绍了如何在不同场景下进行 MySQL 数据库的迁移,包括从一个硬盘迁移到另一个硬盘、从一台计算机迁移到另一台计算机,以及解决迁移过程中可能遇到的问题。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 探讨如何从数据库中按分组获取最大N条记录的方法,并分享新年祝福。本文提供多种解决方案,适用于不同数据库系统,如MySQL、Oracle等。 ... [详细]
  • 本章详细介绍SP框架中的数据操作方法,包括数据查找、记录查询、新增、删除、更新、计数及字段增减等核心功能。通过具体示例和详细解析,帮助开发者更好地理解和使用这些方法。 ... [详细]
  • 本文详细探讨了不同SQL数据库管理系统(DBMS)在限制输出结果、拼接字段和日期时间处理方面的函数差异。通过具体示例,帮助读者理解并掌握如何在不同DBMS中实现相同功能。 ... [详细]
  • 本文详细介绍了IBM DB2数据库在大型应用系统中的应用,强调其卓越的可扩展性和多环境支持能力。文章深入分析了DB2在数据利用性、完整性、安全性和恢复性方面的优势,并提供了优化建议以提升其在不同规模应用程序中的表现。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 配置PHPStudy环境并使用DVWA进行Web安全测试
    本文详细介绍了如何在PHPStudy环境下配置DVWA( Damn Vulnerable Web Application ),并利用该平台进行SQL注入和XSS攻击的练习。通过此过程,读者可以熟悉常见的Web漏洞及其利用方法。 ... [详细]
  • 烤鸭|本文_Spring之Bean的生命周期详解
    烤鸭|本文_Spring之Bean的生命周期详解 ... [详细]
author-avatar
丫头片子ZXH
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有