你要搞清楚自己人生的剧本:不是你父母的续集,不是你子女的前传,更不是你朋友的外篇。对待生命你不妨大胆冒险一点,因为好歹你要失去它。
——尼采
Mybatis
以前做性能测试,需要把测试数据插入到测试数据库里,然后采用的就是最基本的JDBC的方式:
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 通过驱动管理类获取数据库链接
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8",
"root", "root");
// 定义sql语句 ?表示占位符
String sql = "select * from t_user where username = ?";
//获取预处理statement
preparedStatement = connection.prepareStatement(sql);
// 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "王五");
// 向数据库发出sql执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
但是,如果频繁的创建数据库连接和关闭,将会造成数据库性能上的瓶颈,网上也有解决方法,通过连接池管理数据库的连接。还有一个就是,把sql语句硬编码在代码里,也不便于维护。
Mybatis框架的出现就是为了更完美的操作数据库,用网上资料的话说:
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
看到一个小姑娘在网上的绘图mybatis的原理图,觉得非常棒,放在这里。
具体的过程分析可以看她写的文章:
mybatis是什么?写的很好,推荐看看
Mapper
掌握了Mybatis这个神器以后,本来以为可以愉快的实现DAO接口了,结果又发现了一个叫Mapper接口的利器,可以做到跟DAO一样的事情,而且更简单。
DAO接口
如果我们用DAO的话,代码画风是这样的:
public interface UserDao {
public UserInfo getUser(int id) throws Exception;
//添加用户信息
public void insertUser(UserInfo userInfo) throws Exception;
}
***DAO接口的实现****
public class UserDaoImpl implements UserDao{
//需要向dao实现类中注入SqlSessionFactory
//这里通过构造方法注入
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
super();
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User getUser() throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
User user=sqlSession.selectOne("test.getUser", id);
//释放资源
sqlSession.close();
return user;
}
@Override
public void insertUser(UserInfo user) throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser", user);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
}
可以看出,我们可以在DAO的实现类里提取出公共方法。
SqlSession sqlSession=sqlSessionFactory.openSession();
User user=sqlSession.selectOne("test.getUser", id);
SqlSession sqlSession=sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser", user);
于是伟大的Mapper接口排上用处了。程序员只需要写mapper接口(相当于dao接口))就可以了。
它长这个样子,跟DAO接口一样,但不用写Mapper的实现了。
package com.siemens.springb.mapper;
import com.siemens.springb.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserInfoMapper {
//根据具体的id查询user的信息
List<UserInfo> getid(int id);
//查询所有的消息
List<UserInfo> getAll();
//插入数据
void insertUser(UserInfo userInfo);
}
重点来了!!!
如何把刚刚讲到的Mybatis,Mapper结合Spring Boot实现呢?
1、在Build.Gradle里把Mybatis Starter和MySQL的Driver配置好,我假设你的MySQL在本地或者其他地方已经装好了。(我开始没有配置MySQL的driver,导致项目启动后就报错)
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile('org.springframework.boot:spring-boot-starter-test')
compile group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '1.1.1'
compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'
}
顺便多说一句,如果你知道可能要引用的包,不知道Gradle怎么写,可以在Maven Repository里面找到Gradle的相关配置方法,这个好用。
2、创建xxxMapper.xml文件,路径在main/resource/mybatis/下面(mybatis文件夹是我自己手动创建的...)
我们来看看这个xxxMapper.xml文件,非常需要注意的是,这个namespace一定要指向Mapper接口。
<?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">
<!-- namespace必须指向Mapper接口 -->
<mapper namespace="com.siemens.springb.mapper.UserInfoMapper">
<!-- 所有列 -->
<sql id="Column_list">
user_id,
user_name,
user_score
</sql>
<resultMap id="ListTest" type="com.siemens.springb.model.UserInfo" >
<id column="user_id" property="id" />
<result column="user_name" property="name" />
<result column="user_score" property="score" />
</resultMap>
<!-- 根据ID查询数据 -->
<select id="getid" parameterType="int" resultMap="ListTest">
SELECT
<include refid="Column_list" />
FROM user_info WHERE user_id = #{id}
</select>
<!-- 查询所有的数据 -->
<select id="getAll" resultMap="ListTest">
SELECT
<include refid="Column_list" />
FROM user_info
</select>
<!-- 插入User数据 -->
<select id="insertUser" parameterType="com.siemens.springb.model.UserInfo">
INSERT INTO user_info (<include refid="Column_list" />)
VALUES (#{id},#{name},#{score})
</select>
</mapper>
3、在application.propertis里添加MySQL的配置信息,方便从数据库读写数据。
这里/dev_test是我在本地创建的一个数据库名称。
#server configuration
server.port = 8081
server.context-path = /AssetOnboard
#mysql config
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/dev_test?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.max-active=10
spring.datasource.max-idle=5
spring.datasource.min-idle=0
mybatis.mapper-locations=classpath:/mybatis/*.xml
4、创建Mapper接口。这样它就跟mybatis配置文件xxxMapper.xml里的namespace的值对应起来了,namespace = “com.siemens.springb.mapper.UserInfoMapper”。
package com.siemens.springb.mapper;
import com.siemens.springb.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserInfoMapper {
//根据具体的id查询user的信息
List<UserInfo> getid(int id);
//查询所有的消息
List<UserInfo> getAll();
//插入数据
void insertUser(UserInfo userInfo);
}
同时我们看到,getid(int id)、getAll() 和 insertUser(userInfo) 它们3个分别是对应xxxMapper.xml里的<select id="getid"...<select id="getAll"...<select id="insertUser"
对于需要传入参数的int id 和 UserInfo userInfo,在xml里面通过parameter=“int” 和 parameter="com.siemens.springb.model.UserInfo"指定类型。
5、创建POJO类UserInfo
package com.siemens.springb.model;
public class UserInfo {
private int id;
private String name;
private float score;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setScore(float score) {
this.score = score;
}
public float getScore() {
return score;
}
}
6、创建@Service: UserService,将UserInfoMapper接口通过@Autowired注入到Service。
package com.siemens.springb.service;
import com.siemens.springb.BeanWithoutProperties;
import com.siemens.springb.mapper.UserInfoMapper;
import com.siemens.springb.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
//UserInfoMapper注入到Service
@Autowired
UserInfoMapper userInfoMapper;
//根据id返回特定的user信息
public List<UserInfo> getUserInfo(int id){
return userInfoMapper.getid(id);
}
//查询返回所有的用户信息
public List<UserInfo> getAllUserInfo(){
return userInfoMapper.getAll();
}
//插入user info的数据
public void insertUser(UserInfo userInfo){
userInfoMapper.insertUser(userInfo);
}
}
7、再次通过@Autowired把@Service注入到Controller层
package com.siemens.springb;
import com.siemens.springb.model.UserInfo;
import com.siemens.springb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;
import java.util.List;
//表明这是一个 Controller
@Controller
//RestController是一种Rest风格的Controller,可以直接返回对象而不返回视图,返回的对象可以使JSON,XML等
public class SpringController {
//Service注入到Controller
@Autowired
UserService userService;
//mybatis取代简单原始的jdbc,mapper接口取代DAO接口编程,service注入到controller
//根据传入的user_id参数来查询user_info表里指定ID的数据
@RequestMapping("/getUser")
//表示返回JSON格式的结果,如果前面使用的是@RestController可以不用写
@ResponseBody
public String getUsers(@RequestParam("user_id") Integer userId) {
List<UserInfo> userInfo = userService.getUserInfo(userId);
String note = "Note: " + "\n\t" + "mybatis把对数据库的操作进行了封装,取代原始简单的JDBC。 " + "\n\t";
String userDetail = "";
for(UserInfo info:userInfo){
userDetail += "Name: " + info.getName() + " " + "ID: " + info.getId()+ " " + "\n\t";
}
return note + userDetail;
}
//查询user_info表里的所有的user信息
@RequestMapping("/getAllUser")
//表示返回JSON格式的结果,如果前面使用的是@RestController可以不用写
@ResponseBody
public Object getAllUsers() {
List<UserInfo> userInfo = userService.getAllUserInfo();
return userInfo;
}
//插入User Info数据到user_info表
@RequestMapping("/upLoadUserInfo")
//表示返回JSON格式的结果,如果前面使用的是@RestController可以不用写
@ResponseBody
public String upLoadInfo2UserInfo(@RequestParam("user_id") Integer userId, @RequestParam("user_name") String username, float user_score) {
UserInfo userInfo = new UserInfo();
userInfo.setId(userId);
userInfo.setName(username);
userInfo.setScore(user_score);
userService.insertUser(userInfo);
return "Insert Success";
}
}
8、开始测试下:
写入数据到mySql: /upLoadUserInfo/user_id=52&user_name=stevenJia&user_score=10.0
image.png
ToDo:
1、代码这里没有做异常的处理,也还没有相应的log日志记录。
2、增加Junit测试代码
总结下:
在Spring Boot里其实是不推荐使用导入xml配置的,boot加载了默认配置,适用于大多数场景,但不是说就不能导入xml,并且它同样提供了强大的mvc的配置和自定义的配置,后面可以研究下。
参考文献
Mybatis从Spring MVC到Spring Boot,请一定要看!
妹纸写的Mapper接口和DAO接口的区别,也非常不错!
GitHub上一个很简单的例子可以更好的认清Spring Boot + Mybatis + Mapper的用法
网友评论