一、MyBatis框架的搭建及查询实现
Mybatis 开源免费框架.原名叫iBatis,2010在google code,2013年迁移到 github
作用: 数据访问层框架.底层是对 JDBC 的封装.
mybatis 优点之一:使用mybatis 时不需要编写实现类,只需要写需要执行的 sql 命令
环境搭建:
1.导入相关jar包,下图所示是mybatis框架所需核心包及相关支持包。
![]()
因为我们涉及查询在jsp页面展示,所以还需要导入jstl相关jar:
2.在src下编写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="dev"> <environment id="dev"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/ssm"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/tao/mapper/PeopleMapper.xml"/> </mappers> </configuration>
可以配置多个数据源,选择自己默认使用的即可。
<transactionManager/> type 属性可取值:
JDBC,事务管理使用 JDBC 原生事务管理方式;
MANAGED 把事务管理转交给其他容器.原生 JDBC 事务
<dataSouce/>type 属性:
POOLED 使用数据库连接池;UNPOOLED 不实用数据库连接池,和直接使用 JDBC 一样;
JNDI :java 命名目录接口技术.
另外:mybaits.xml不一定非得放在src下,项目编译打包后src下的文件是在classes文件夹下,服务器也是默认从classes目录去找,假设我们在src下建立了一个 src/config 的包 那到时候我们加载的时候 就在路径前面加上 config/mybatis.xml即可。
3.编写实体类 以及 对应的Mapper.xml文件:
工程结构:
People:
package com.tao.pojo; public class People { private int id; private String name; private int age; 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 int getAge() { return age; } public void setAge(int age) { this.age = age; } }
PeopleMapper.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"> <!-- 此处namespace 后续写上对应接口名称 暂时写什么都行 --> <mapper namespace="com.tao.mapper.PeopleMapper"> <select id="selectAll" resultType="com.tao.pojo.People"> select * from people </select> </mapper>
关于Mapper.xml 要说的几点:
id方法名 parameterType:定义参数类型 resultType:放回值类型(如果方法返回值是list,在resultType中写List的泛型,因为mybatis是对jdbc的封装,一行一行的读取数据) 要注意的是:1.返回的对象 如果属性名和数据库的字段名一致,那么mybatis底层会调用反射解析找到set方法 进行自动字段映射 如果不一致 则可能查出来的是null 2.部分字段不一致时,我们可以采用起别名的方式,例如:select id as roleId,role_name as roleName,usergroup_id as usergroupId,create_at as createAt,status,remark from t_role
业务层接口:PeopleService:
package com.tao.service; import java.io.IOException; import java.util.List; import com.tao.pojo.People; public interface PeopleService { /** * 显示全部 * @return * @throws IOException */ List<People> show() throws IOException; }
业务层实现类:PeopleServiceImpl
package com.tao.service.impl; import java.io.IOException; import java.io.InputStream; import java.util.List; 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 com.tao.pojo.People; import com.tao.service.PeopleService; /** * 在数据访问层处理异常和控制器中处理异常,service中只抛出异常 * @author TaoGG * */ public class PeopleServiceImpl implements PeopleService{ @Override public List<People> show() throws IOException { InputStream inputStream = Resources.getResourceAsStream("mybatis.xml"); //前面是工厂 实例化工厂对象时使用的是 构建者设计模式 名称标志:后面有Builder //构建者设计模式存在的意义:简化对象实例化的过程 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); List<People> peopleList = session.selectList("com.tao.mapper.PeopleMapper.selectAll"); session.close(); return peopleList; } }
刚刚说的mybatis路径问题,指的就是这边解析时:
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml"); 如果mybatis.xml 是在src/config下,那这句代码就得这么写: InputStream inputStream = Resources.getResourceAsStream("config/mybatis.xml");
目前我们单个框架都是手动解析 和spring整合以后 这些解析代码就不需要我们做了。
最后写上控制层:PeopleServlet
package com.tao.servlet; import java.io.IOException; import java.util.List; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.tao.pojo.People; import com.tao.service.PeopleService; import com.tao.service.impl.PeopleServiceImpl; //大部分注解都有默认属性,如果注解中只给默认属性赋值,我们可以省略属性名 //否则在注解的(属性名=属性值)格式 //如果一个属性是数组类型 格式:属性名={值,值} 如果该数组只有一个值 可以省略大括号 //如果类型不是基本数据类型或String 而是一个类类型 语法:属性名[email protected]类型 //注解中@表示引用注解声明 @WebServlet("/peopleShow") public class PeopleServlet extends HttpServlet{ private static final long serialVersionUID = 1L; private PeopleService peopleService = new PeopleServiceImpl(); @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { List<People> list = peopleService.show(); req.setAttribute("list", list); //相对路径 //只要路径中以/开头的 都叫全路径 //只要不以/开头的都是相对路径 相对路径是从当前资源出发找到其他资源的过程 //全路径是从项目根目录(webContent) 出发去找其他资源的过程 //如果请求转发 / 表示webContent 目录 //如果是重定向,静态资源引用 比如<img> <a href=""> <script src="" /> css等引用是 其中 / 都表示tomcat的webapps文件夹根目录 也就是服务器根目录 req.getRequestDispatcher("/index.jsp").forward(req, resp); } }
这边特别强调一下备注信息:
注解方面:
//大部分注解都有默认属性,如果注解中只给默认属性赋值,我们可以省略属性名
//否则在注解的(属性名=属性值)格式
//如果一个属性是数组类型 格式:属性名={值,值} 如果该数组只有一个值 可以省略大括号
//如果类型不是基本数据类型或String 而是一个类类型 语法:属性名[email protected]类型
//注解中@表示引用注解声明
@WebServlet("/peopleShow")路径方面:
//相对路径
//只要路径中以/开头的 都叫全路径
//只要不以/开头的都是相对路径 相对路径是从当前资源出发找到其他资源的过程
//全路径是从项目根目录(webContent) 出发去找其他资源的过程
//如果请求转发 / 表示webContent 目录
//如果是重定向,静态资源引用 比如<img> <a href=""> <script src="" /> css等引用是 其中 / 都表示tomcat的webapps文件夹根目录 也就是服务器根目录这些都是写项目容易错的地方。
在webcontent下新建一个index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <table border="0"> <tr> <th>编号</th> <th>姓名</th> <th>年龄</th> </tr> <c:forEach items="${list}" var="people"> <tr> <td>${people.id}</td> <td>${people.name}</td> <td>${people.age}</td> </tr> </c:forEach> </table> </body> </html>
最后我们页面请求一下:
另外再介绍一些简单的查询方式,例子是来自其他Demo 但原理都差不多:
1.适用于查询结果都需要遍历的需求:
selectList() 返回值为 List<resultType 属性控制>
sql:
<select id="selectAllRole" resultType="com.tao.entity.Role"> select id as roleId,role_name as roleName,usergroup_id as usergroupId,create_at as createAt,status,remark from t_role </select>
code:
List<Role> list = session.selectList("a.b.selectAllRole"); for (Role role : list) { System.out.println(role.toString()); }
2.适用于返回结果只是变量或一行数据时:
selectOne() 返回值 Object 可根据需要 返回指定对象
sql:
<select id="selectRoleById" resultType="java.lang.Integer"> select count(*) from t_role </select>
code:
Integer count = session.selectOne("a.b.selectRoleById"); System.out.println(count); session.close();
3.适用于需要在查询结果中通过某列的值取到这行数据的需求,比如电话簿的map根据名字找联系人 这样检索快
Map<key,resultType 控制>
sql:
<select id="selectRoleNameByMap" resultType="com.tao.entity.Role"> select id as roleId,role_name as roleName,usergroup_id as usergroupId,create_at as createAt,status,remark from t_role </select>
code:
//把数据库中哪个列的值当作map的key Map<Object, Object> selectMap = session.selectMap("a.b.selectRoleNameByMap", "roleName"); System.out.println(selectMap);