什么是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语句复用甚至是加入缓存提高查询速度,框架都帮你做好了。