MyBatis与传统JDBC的比较

什么是MyBatis?

简单来说,这是一个在你和数据库打交道的时候能够让你把精力更多的放在SQL语句而不是对象封装上的框架。

更简单的来说,就是能够帮你节省时间、提高效率的工具。就像盖一座小木屋,以前需要自己画图、自己伐木、自己盖房子,但是用了框架,就像请了施工队,只需要自己画图,剩下的交给施工队就OK啦。

思考这样的一个问题

我们的数据库中有一个user表,字段包含name、age、gender、address,相对应的有一个User实体类,有属性name、age、gender、address。

此时我们需要查询到这个表中的所有信息,SQL语句是

select * from user

和数据库进行交互的是UserDao接口,其中有一个方法

public interface UserDao {
    List<User> findAll ();
}

这时该怎么办?

首先创建一个UserDao的实现类UserDaoImpl,实现findAll()方法

public class UserDaoImpl implements UserDao {

    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<User> findAll() {
        Connection connection = null;
        PreparedStatement statement = null;
        List<User> users = new ArrayList<>();

        try {
            connection = DriverManager.getConnection("jdbc:mysql:///test?serverTimezone=CTT", "root", "1229");
            String sql = "select * from user";
            statement = connection.prepareStatement(sql);
            ResultSet resultSet = statement.executeQuery();
            while (resultSet.next()) {
                User user = new User();
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                String gender = resultSet.getString("gender");
                String address = resultSet.getString("address");
                user.setName(name);
                user.setAge(age);
                user.setGender(gender);
                user.setAddress(address);
                users.add(user);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

        return users;
    }
}

写一个测试类测试一下:

public class TestUserDao {

    @Test
    public void testFindAll () {
        UserDao userDao = new UserDaoImpl();
        List<User> users = userDao.findAll();

        for (User user : users) {
            System.out.println(user);
        }
    }
}

是不是看起来非常麻烦,我们需要先注册驱动,再连接数据库,然后才到了我们最关心的SQL语句,可是在这之后还需要执行语句、封装对象、处理异常。

我们真正关心的只有一行代码,可是却需要写几十行不得不写代码,这还只是最简单的查询,一旦加上别的处理逻辑,还不得疯了。

接下来看看MyBatis做这个查询需要做什么

首先,实现类不需要了(当然也可以有,那种方法是利用纯XML映射器,这里只展示XML映射器+接口映射器)

创建一个MyBatis的配置XML(官方名称叫做映射器)

<?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>
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///test?serverTimezone=CTT"/>
                <property name="username" value="root"/>
                <property name="password" value="1229"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="UserDao.xml"/>
    </mappers>
</configuration>

可以很清楚的看出,这个配置文件中设置了mysql的驱动位置、url、用户名和密码,其他的先不用关心。

然后在<mappers>标签中设置了上文提到的接口映射器UserDao.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="UserDao">
    <select id="findAll" resultType="User">
        select * from user
    </select>
</mapper>

这里我们需要注意的是:<mapper>标签的namespace属性设置了接口的全限定类名(我为了省事没有把类放在不同的包,实际项目这里要填写具体的包名+类名)

select标签的id属性设置了接口中的findAll()方法名,resultType属性设置了返回值的全限定类名。

select标签体里就是我们最关心的SQL语句。

测试一下:

    @Test
    public void testFindAll2 () throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        InputStream is = Resources.getResourceAsStream("mybatis_config.xml");
        SqlSessionFactory factory = builder.build(is);
        SqlSession sqlSession = factory.openSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

也许看到这有的人会说这也没简单多少啊,确实一条SQL语句体现不出mybatis的简便之处。

如果我们现在要多表联合查询,返回不同表中的特定字段,该怎么办?

想一想就很复杂,但是即使是这种复杂的逻辑,MyBatis也已经为我们做好了处理规范。

 

总而言之,MyBatis相较于JDBC,就好比专业施工团队相较于锤头木锯,你想要的,你能想到的,框架都帮你实现了,无论是条件查询、多表联合查询、SQL语句复用甚至是加入缓存提高查询速度,框架都帮你做好了。


版权声明:本文为sirius_black_tea原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。