前言
在了解了JDBC的不足之后,我们来进行MyBatis的学习。
正文
java工程独立使用mybatis
我们先来使用原生的java结合mybatis操作数据库,依然是前一篇博文中创建的user表,我们使用mybatis通过uid来查找一个用户。
首先我们创建一个java工程,并且将mybatis的相关jar引入:
通过上一篇文章的架构图,我们可以看到,mybatis的最上层是sqlmapconfig文件,因此我们来创建一个配置文件SqlMapConfig.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>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理-->
<transactionManager type="JDBC" />
<!-- 数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/jdbc?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>
</configuration>
除此之外,我们还应该建立一个实体类pojo,对应数据库中的user表:
package com.mybatis.po;
public class User {
private int uid;
private String username;
private String password;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [uid=" + uid + ", username=" + username + ", password=" + password + "]";
}
}
接下来,我们在classpath目录下创建一个sqlmap文件夹,并在里面新建一个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">
<mapper namespace="mybatis">
<select id="findUserById" parameterType="int" resultType="com.mybatis.po.User">
select * from user where uid = #{id}
</select>
</mapper>
在这个文件中,有个namespace,这个是每个映射文件的命名空间。
按照文件的类型,在SqlMapConfig.xml中是要加载这个User.xml文件的,我已经在上面的代码中加载过了:
<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>
注意,在User.xml文件中,我们写了一个select标签,这个标签中有自定义的sql语句,在这个标签中:
- parameterType:定义输入到sql中的参数类型.
- #{id}表示使用preparedstatement设置占位符号,并将输入变量id输入到sql中。
- resultType:定义结果映射类型,即sql语句执行结果的类型,在这里我们使用了User对象来接受查询的结果,mybatis会将查询结果自动封装到User对象中去。
接下来我们来测试一下这个sql:
package com.mybatis.test;
import java.io.IOException;
import java.io.InputStream;
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.Before;
import org.junit.Test;
import com.mybatis.po.User;
public class UserTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void createSqlSessionFactory() throws IOException {
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
//根据用户id查询用户信息
User user = sqlSession.selectOne("mybatis.findUserById", 2);
System.out.println(user);
}catch (Exception e) {
e.printStackTrace();
}finally {
if (sqlSession != null ) {
sqlSession.close();
}
}
}
}
**看以上的代码,我们在运行测试方法值钱,先执行一个createSqlSessionFactory的方法,通过架构图我们看到,
我们是使用sqlSession来操作数据库的,而sqlSession来源于sqlSessionFactory,sqlSessionFactory对象其实就是SqlMapConfig配置文件经过转化后封装对象,因为我们在这里要提前创建sqlSessionFactory**
以上测试方法的执行结果如下:
查看输入信息,我们发现mybatis已经将我们写的sql和调用方法传入的参数自动装配,并且也将结果查询出来了。在这里我们使用的sqlSession.selectOne()方法代表查询的结果是一条记录,如果有多条,我们可以使用selectList()方法。
下面我们来使用selectList()方法根据用户名查询用户信息:
首先在User.xml中添加以下代码:
<select id="findUserByName" parameterType="String" resultType="com.mybatis.po.User">
select * from user where username like '%${value}%'
</select>
编写对应的测试方法:
@Test
public void testFindUserByName() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
//根据用户名查询用户信息
List<User> list = sqlSession.selectList("mybatis.findUserByName", "张");
for (User user : list) {
System.out.println(user);
}
}catch (Exception e) {
e.printStackTrace();
}finally {
if (sqlSession != null ) {
sqlSession.close();
}
}
}
可以看到我们查询到了结果:
在这里,需要注意以下几点:
1. 如果sql查询结果是一个List,那么resultType的类型就是该集合中的每一个元素的类型.
2. 和前面不同的是,这里使用了${},在前面的sql中,#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型的转换,切可以防止sql注入.#{}可以接受简单类型值或者pojo属性值.如果parameterType传输单个简单类型值,#{}括号中可以是value或者其他名称.
3. ${}是字符串拼接指令,表示拼接sql串,通过${}
可以将parameterType传入的内容拼接在sql中,且不进行jdbc类型转换,${}
可以接收简单类型值或者pojo属性值,如果parameterType传输单个简单数据类型值,${}
括号中只能是value
4. parameterType指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中.
5. resultType指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象.
插入数据以及主键返回
依旧是上面的User.xml中,我们来编写一个插入新用户的sql:
<!-- 新增用户信息 -->
<insert id="insertUser" parameterType="com.mybatis.po.User">
insert into
user (username, password)
value (#{username}, #{password})
</insert>
继续测试插入数据的方法:
@Test
public void testInsertUser() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
//添加新用户
User user = new User();
user.setUsername("小李");
user.setPassword("111111");
sqlSession.insert("mybatis.insertUser", user);
//新增数据需要提交事务
sqlSession.commit();
}catch (Exception e) {
e.printStackTrace();
}finally {
if (sqlSession != null ) {
sqlSession.close();
}
}
}
刷新数据中的数据,可以看到数据已经插入成功:
因为我们在数据库中的user表中使用的是主键自增长,因此我们在插入数据后可以通过以下方式来得到新添加记录的主键:
修改User.xml中的insert语句:
<!-- 新增用户信息 -->
<insert id="insertUser" parameterType="com.mybatis.po.User">
<selectKey keyProperty="uid" order="AFTER" resultType="Integer">
select LAST_INSERT_ID()
</selectKey>
insert into
user (username, password)
value (#{username}, #{password})
</insert>
这样就可以在插入数据后直接获得用户记录的uid:
在insert语句中添加selectKey将实现主键返回
keyProperty:返回的主键存储在pojo的哪个属性中
order:selectKey的执行顺序,是相对于insert语句来说的,由于mysql的自增原理是执行完insert语句之后才生成主键,因此这里执行顺序为after
resultType:返回的主键类型
LAST_INSERT_ID()
是mysql的函数,返回auto_increment自增列新记录的id值.
类似的,也可以在插入数据前就设置pojo的主键,除了自己设置以外,也可以使用mysql的uuid()函数来实现:
我们在User.xml中添加一个插入的语句:
<insert id="insertUserWithId" parameterType="com.mybatis.po.User">
<selectKey resultType="String" order="BEFORE"
keyProperty="uid">
select uuid()
</selectKey>
insert into
user (uid, username, password)
value (#{uid}, #{username}, #{password})
</insert>
测试代码如下:
@Test
public void testInsertUserWwith() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
//添加新用户
User user = new User();
user.setUsername("大王");
user.setPassword("666");
sqlSession.insert("mybatis.insertUserWithId", user);
//新增数据需要提交事务
sqlSession.commit();
System.out.println("插入记录的id是:" + user.getUid());
}catch (Exception e) {
e.printStackTrace();
}finally {
if (sqlSession != null ) {
sqlSession.close();
}
}
}
注意,在这里我们传入的User对象是没有uid的,数据库会在插入数据前,先使用mysql的函数生成一个uuid作为主键,然后添加都User对象中,再去插入数据库,我们可以通过控制台的输出看到这个过程
其他的删除或者更新的功能也大致一样,这里不再赘述
总结
我们使用mybatis对数据库进行操作后,到底带来了那些方便呢?
- 在SqlMapConfig.xml中,我们配置了数据库连接池,不用频繁的创建连接,耗费性能.
- sql语句配置在xml映射文件中,和java代码分离,便于维护.
- 将java对象映射到sql中,通过statement中的parameterType定义输入参数的类型.
- Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型.