集成MyBatis分别介绍注解方式以及XML方式的整合,喜欢哪种方式自己选择
添加依赖
这里需要添加mybatis-spring-boot-starter依赖跟mysql依赖
<!--最新版本,匹配spring Boot1.5 or higher-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
这里不引入spring-boot-starter-jdbc依赖,是由于mybatis-spring-boot-starter中已经包含了此依赖。
博主开始整理的时候发现mybatis-spring-boot-starter
有新版本了,这里就集成最新的,匹配Spring Boot1.5版本。
MyBatis-Spring-Boot-Starter依赖将会提供如下:
- 自动检测现有的DataSource
- 将创建并注册SqlSessionFactory的实例,该实例使用SqlSessionFactoryBean将该DataSource作为输入进行传递
- 将创建并注册从SqlSessionFactory中获取的SqlSessionTemplate的实例。
- 自动扫描您的mappers,将它们链接到SqlSessionTemplate并将其注册到Spring上下文,以便将它们注入到您的bean中。
就是说,使用了该Starter之后,只需要定义一个DataSource即可(application.properties中可配置),它会自动创建使用该DataSource的SqlSessionFactoryBean以及SqlSessionTemplate。会自动扫描你的Mappers,连接到SqlSessionTemplate,并注册到Spring上下文中。
数据源配置
在src/main/resources/application.properties中配置数据源信息。
spring.datasource.url = jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
自定义数据源
Spring Boot默认使用tomcat-jdbc数据源,如果你想使用其他的数据源,比如这里使用了阿里巴巴的数据池管理,除了在application.properties
配置数据源之外,你应该额外添加以下依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.19</version>
</dependency>
修改Application.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Autowired
private Environment env;
//destroy-method="close"的作用是当数据库连接不使用的时候,就把该连接重新放到数据池中,方便下次使用调用.
@Bean(destroyMethod = "close")
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));//用户名
dataSource.setPassword(env.getProperty("spring.datasource.password"));//密码
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setInitialSize(2);//初始化时建立物理连接的个数
dataSource.setMaxActive(20);//最大连接池数量
dataSource.setMinIdle(0);//最小连接池数量
dataSource.setMaxWait(60000);//获取连接时最大等待时间,单位毫秒。
dataSource.setValidationQuery("SELECT 1");//用来检测连接是否有效的sql
dataSource.setTestOnBorrow(false);//申请连接时执行validationQuery检测连接是否有效
dataSource.setTestWhileIdle(true);//建议配置为true,不影响性能,并且保证安全性。
dataSource.setPoolPreparedStatements(false);//是否缓存preparedStatement,也就是PSCache
return dataSource;
}
}
ok这样就算自己配置了一个DataSource,Spring Boot会智能地选择我们自己配置的这个DataSource实例。
脚本初始化
CREATE DATABASE /*!32312 IF NOT EXISTS*/`spring` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `spring`;
/*Table structure for table `emp` */
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`empid` int(11) NOT NULL AUTO_INCREMENT,
`empname` varchar(20) DEFAULT NULL,
`password` varchar(20) DEFAULT NULL,
PRIMARY KEY (`empid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
/*Data for the table `emp` */
insert into `emp`(`empid`,`empname`,`password`) values (1,'jone','123'),(2,'tom','123'),(3,'lisi','123'),(4,'lisisi','123');
实体对象
public class Emp {
private int empId;
private String empName;
private String password;
// SET和GET方法
}
编写Dao层
接下来,我们分别来介绍下注解方式以及XML配置方式。
方案一:注解方式
Mybatis注解的方式好简单,只要定义一个dao接口,然后sql语句通过注解写在接口方法上。最后给这个接口添加@Mapper注解或者在启动类上添加@MapperScan(“com.it.store.dao”)注解都行。
如下:
package com.it.store.dao;
/**
* Created by tengj on 2017/4/22.
* Component注解不添加也没事,只是不加service那边引入LearnMapper会有错误提示,但不影响
*/
@Component
@Mapper
public interface LearnMapper {
@Insert("insert into learn_resource(author, title,url) values(#{author},#{title},#{url})")
int add(LearnResouce learnResouce);
@Update("update learn_resource set author=#{author},title=#{title},url=#{url} where id = #{id}")
int update(LearnResouce learnResouce);
@DeleteProvider(type = LearnSqlBuilder.class, method = "deleteByids")
int deleteByIds(@Param("ids") String[] ids);
@Select("select * from learn_resource where id = #{id}")
@Results(id = "learnMap", value = {
@Result(column = "id", property = "id", javaType = Long.class),
@Result(property = "author", column = "author", javaType = String.class),
@Result(property = "title", column = "title", javaType = String.class)
})
LearnResouce queryLearnResouceById(@Param("id") Long id);
@SelectProvider(type = LearnSqlBuilder.class, method = "queryLearnResouceByParams")
List<LearnResouce> queryLearnResouceList(Map<String, Object> params);
class LearnSqlBuilder {
public String queryLearnResouceByParams(final Map<String, Object> params) {
StringBuffer sql =new StringBuffer();
sql.append("select * from learn_resource where 1=1");
if(!StringUtil.isNull((String)params.get("author"))){
sql.append(" and author like '%").append((String)params.get("author")).append("%'");
}
if(!StringUtil.isNull((String)params.get("title"))){
sql.append(" and title like '%").append((String)params.get("title")).append("%'");
}
System.out.println("查询sql=="+sql.toString());
return sql.toString();
}
//删除的方法
public String deleteByids(@Param("ids") final String[] ids){
StringBuffer sql =new StringBuffer();
sql.append("DELETE FROM learn_resource WHERE id in(");
for (int i=0;i<ids.length;i++){
if(i==ids.length-1){
sql.append(ids[i]);
}else{
sql.append(ids[i]).append(",");
}
}
sql.append(")");
return sql.toString();
}
}
}
需要注意的是,简单的语句只需要使用@Insert、@Update、@Delete、@Select这4个注解即可,但是有些复杂点需要动态SQL语句,就比如上面方法中根据查询条件是否有值来动态添加sql的,就需要使用@InsertProvider、@UpdateProvider、@DeleteProvider、@SelectProvider等注解。
这些可选的 SQL 注解允许你指定一个类名和一个方法在执行时来返回运行 允许创建动态 的 SQL。 基于执行的映射语句, MyBatis 会实例化这个类,然后执行由 provider 指定的方法. 该方法可以有选择地接受参数对象.(In MyBatis 3.4 or later, it’s allow multiple parameters) 属性: type,method。type 属性是类。method 属性是方法名。 注意: 这节之后是对 类的 讨论,它可以帮助你以干净,容于阅读 的方式来构建动态 SQL。
方案二:XML配置方式
xml配置方式保持映射文件的老传统,优化主要体现在不需要实现dao的是实现层,系统会自动根据方法名在映射文件中找对应的sql,具体操作如下:
新建EmpMapper接口,无需具体实现类。
package com.it.store.dao;
import com.it.store.entity.Emp;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface EmpMapper {
int add(Emp emp);
int update(Emp emp);
int delete(int empId);
List<Emp> queryAll(Emp emp);
Emp queryById(int empId);
int login(Emp emp);
}
修改application.properties 配置文件
#指定bean所在包
mybatis.type-aliases-package=com.it.store.entity
#指定映射文件
mybatis.mapperLocations=classpath:mapper/*.xml
添加LearnMapper的映射文件
在src/main/resources目录下新建一个mapper目录,在mapper目录下新建EmpMapper.xml文件。
通过mapper标签中的namespace属性指定对应的dao映射,这里指向EmpMapper。
更多mybatis数据访问操作的使用请参考:mybatis官方中文参考文档
<?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="com.it.store.dao.EmpMapper">
<select id="queryById" resultType="Emp" parameterType="int">
select * from Emp where empid = #{empid}
</select>
<insert id="add" parameterType="Emp" >
insert into emp values(#{empId},#{empName},#{password})
</insert>
<update id="update" parameterType="Emp">
update emp set empName=#{empName},passwrod=#{password} where empid=#{empId}
</update>
<delete id="delete" parameterType="int">
delete from emp where empId=#{empId}
</delete>
<select id="queryAll" parameterType="Emp" resultType="Emp">
select * from emp where 1=1
<if test="empName!=null">
and empName like '%{empName}%'
</if>
</select>
<select id="login" parameterType="Emp" resultType="int">
select * from emp where empName=#{empName} and password=#{password}
</select>
</mapper>
以上是dao层两种实现方式,以下是通用代码模块
Service层
public interface EmpService {
int add(Emp emp);
int update(Emp emp);
int delete(int empId);
List<Emp> queryAll(Emp emp);
Emp queryById(int empId);
int login(Emp emp);
}
实现类
package com.it.store.service.impl;
import com.it.store.dao.EmpMapper;
import com.it.store.entity.Emp;
import com.it.store.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmpServiceImpl implements EmpService {
private EmpMapper empMapper;
@Autowired
public void setEmpMapper(EmpMapper empMapper) {
this.empMapper = empMapper;
}
@Override
public int add(Emp emp) {
return empMapper.add(emp);
}
@Override
public int update(Emp emp) {
return empMapper.update(emp);
}
@Override
public int delete(int empId) {
return empMapper.delete(empId);
}
@Override
public List<Emp> queryAll(Emp emp) {
return empMapper.queryAll(emp);
}
@Override
public Emp queryById(int empId) {
return empMapper.queryById(empId);
}
@Override
public int login(Emp emp) {
return empMapper.login(emp);
}
}
Controller层
@Controller
@RequestMapping("/emp")
public class EmpController {
private EmpService empService;
@Autowired
public void setEmpService(EmpService empService) {
this.empService = empService;
}
Logger log= LoggerFactory.getLogger(EmpController.class);
@RequestMapping(value = "toLogin",method = RequestMethod.GET)
public String toLogin(){
return "login";
}
@RequestMapping(value = "login",method = RequestMethod.POST)
@ResponseBody
public Object login(HttpServletRequest request, HttpServletResponse response){
log.debug("start to login");
Map<String,Object> map =new HashMap<>();
String empName=request.getParameter("empName");
String password=request.getParameter("password");
Emp emp=new Emp(0,empName,password);
int result=empService.login(emp);
if(result>0){
request.getSession().setAttribute("user",emp);
map.put("result","1");
}else{
map.put("result","0");
}
return map;
}
@RequestMapping("/showEmp")
public ModelAndView showEmp(){
ModelAndView mav=new ModelAndView("/show");
List list=new ArrayList<Emp>();
Emp emp=new Emp();
list=empService.queryAll(emp);
mav.addObject("list",list);
return mav;
}
@RequestMapping("/toAdd")
public String toAdd(){
log.debug("toAdd");
return "/add";
}
@RequestMapping(value = "/add",method = RequestMethod.POST)
public String add(Emp emp){
int result=empService.add(emp);
if(result>0){
return "redirect:/emp/showEmp";
}else{
return "/toAdd";
}
}
修改页面是Html页面如果不采用异步要采用Thymeleaf中的th:value的方法来给表单赋值:
<!DOCTYPE html><!--如果没有th:提示可以把改成此外这样就没问题了-->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="description" content=""/>
<title>修改</title>
<link rel="stylesheet" href="../static/css/jq22.css" th:href="@{/css/jq22.css}"/>
</head>
<body>
<!-- begin -->
<div id="login">
<div class="wrapper">
<div class="login">
<form action="update" method="post" class="container offset1 loginform">
<div class="pad">
<input type="hidden" name="_csrf" value="9IAtUxV2CatyxHiK2LxzOsT6wtBE6h8BpzOmk="/>
<div class="control-group">
<div class="controls">
<label for="empName" class="control-label fa fa-envelope"></label>
<input id="empName" th:value='${emp.empName}' type="text" name="empName" placeholder="empName" tabindex="1"
autofocus="autofocus" class="form-control input-medium" />
</div>
</div>
<div class="control-group">
<div class="controls">
<label for="password" class="control-label fa fa-asterisk"></label>
<input id="password" type="password" name="password" placeholder="Password" tabindex="2"
class="form-control input-medium" th:value='${emp.password}'/>
</div>
</div>
</div>
<div class="form-actions">
<input type="hidden" name="empId" th:value="${emp.empId}"/>
<button type="submit" tabindex="4" class="btn btn-primary">提交</button>
</div>
</form>
</div>
</div>
<script src="../static/js/jquery.min.js" th:src="@{/js/jquery.min.js}"></script>
</div>
<!-- end -->
</body>
</html>