mybatis-三行代码实现分页

关于分页这个,基本上在后台查询数据的时候都会用到,这里介绍一个非常简单的插件工具PageHelper,实现三行代码实现分页(其实也不是三行代码,还有一个实体类工具mybatis的配置文件需要做一个简单的修改,但是在controller里面确是实实在在的三行代码)。

首先贴上插件工具的Gitup地址:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md

这里只是用来记录一下自己的实例,可以帮助小白快速实现分页的需求。

使用方法:

1.引入分页插件

引入分页插件有下面2种方式,推荐使用 Maven 方式。

1). 引入 Jar 包
你可以从下面的地址中下载最新版本的 jar 包(建议用链接2下载比较快,直接选用最下面的新版本即可)

https://oss.sonatype.org/content/repositories/releases/com/github/pagehelper/pagehelper/

http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/

由于使用了sql 解析工具,你还需要下载 jsqlparser.jar:

http://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/0.9.5/

2). 使用 Maven

在 pom.xml 中添加如下依赖:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>最新版本</version>
</dependency>

最新版本号可以从首页查看:http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/

2. 配置拦截器插件

特别注意,新版拦截器是 com.github.pagehelper.PageInterceptor。(PageInterceptor这个工具类是需要加在项目里面的,后面会贴上,com.github.pagehelper是类所在的包名)。
com.github.pagehelper.PageHelper 现在是一个特殊的 dialect 实现类,是分页插件的默认实现类,提供了和以前相同的用法。

  • 1.在 MyBatis 配置 xml 中配置拦截器插件
<!-- 
    plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
    properties?, settings?, 
    typeAliases?, typeHandlers?, 
    objectFactory?,objectWrapperFactory?, 
    plugins?, 
    environments?, databaseIdProvider?, mappers?
-->
<plugins>
    <!-- com.github.pagehelper为PageHelper类所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
        <property name="param1" value="value1"/>
	</plugin>
</plugins>

这里贴上我的mybatis的配置文件:

<?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>
	<!-- 别名定义 -->
	<typeAliases>
		<package name="com.zih.po" />
	</typeAliases>

	<!-- 分页工具的配置 -->
	<plugins>
		<!--PageInterceptor放在了com.zih.utils包下-->
		<plugin interceptor="com.zih.utils.PageInterceptor">
			<!-- config params as the following -->
			<!--<!–分页参数合理化 –> -->
			<property name="reasonable" value="true" />
		</plugin>
	</plugins>
</configuration>

一些配置参数的说明可以参考文档: 【分页插件参数介绍】

这里就说明一下reasonable的配置:

reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页,pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。

那么如何选择这些配置参数,文档中也给出了详细说明:【如何选择配置这些参数】

最后就是在代码中使用了,这个才是我们关心的问题:

官方文档也有这部分说明和案例,但是作为小白的我,看了之后仍然懵逼,没有实例演示来得快,感觉这种拿来就能用的才是最好的,哈哈,接下来,我以我的项目为例,来演示如何使用,此博客适合我这种小白水平的新手使用,大神可略过,有什么不正确的地方,还请看出来的前辈帮忙指正一下。

首先我的项目结构如图所示:
这里写图片描述

其中PageInterceptor工具类是分页必须要添加的,否则会导致分页失败,直接查全部的数据了,内容如下:

package com.zih.utils;

import com.github.pagehelper.Dialect;
import com.github.pagehelper.PageException;
import com.github.pagehelper.cache.Cache;
import com.github.pagehelper.cache.CacheFactory;
import com.github.pagehelper.util.MSUtils;
import com.github.pagehelper.util.StringUtil;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * Mybatis - 通用分页拦截器<br/>
 * 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper
 *
 * @author liuzh/abel533/isea533
 * @version 5.0.0
 */
@SuppressWarnings({"rawtypes", "unchecked"})
@Intercepts(
    {
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
    }
)
public class PageInterceptor implements Interceptor {
    //缓存count查询的ms
    protected Cache<String, MappedStatement> msCountMap = null;
    private Dialect dialect;
    private String default_dialect_class = "com.github.pagehelper.PageHelper";
    private Field additionalParametersField;
    private String countSuffix = "_COUNT";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        try {
            Object[] args = invocation.getArgs();
            MappedStatement ms = (MappedStatement) args[0];
            Object parameter = args[1];
            RowBounds rowBounds = (RowBounds) args[2];
            ResultHandler resultHandler = (ResultHandler) args[3];
            Executor executor = (Executor) invocation.getTarget();
            CacheKey cacheKey;
            BoundSql boundSql;
            //由于逻辑关系,只会进入一次
            if(args.length == 4){
                //4 个参数时
                boundSql = ms.getBoundSql(parameter);
                cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
            } else {
                //6 个参数时
                cacheKey = (CacheKey) args[4];
                boundSql = (BoundSql) args[5];
            }
            List resultList;
            //调用方法判断是否需要进行分页,如果不需要,直接返回结果
            if (!dialect.skip(ms, parameter, rowBounds)) {
                //反射获取动态参数
                String msId = ms.getId();
                Configuration configuration = ms.getConfiguration();
                Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
                //判断是否需要进行 count 查询
                if (dialect.beforeCount(ms, parameter, rowBounds)) {
                    String countMsId = msId + countSuffix;
                    Long count;
                    //先判断是否存在手写的 count 查询
                    MappedStatement countMs = getExistedMappedStatement(configuration, countMsId);
                    if(countMs != null){
                        count = executeManualCount(executor, countMs, parameter, boundSql, resultHandler);
                    } else {
                        countMs = msCountMap.get(countMsId);
                        //自动创建
                        if (countMs == null) {
                            //根据当前的 ms 创建一个返回值为 Long 类型的 ms
                            countMs = MSUtils.newCountMappedStatement(ms, countMsId);
                            msCountMap.put(countMsId, countMs);
                        }
                        count = executeAutoCount(executor, countMs, parameter, boundSql, rowBounds, resultHandler);
                    }
                    //处理查询总数
                    //返回 true 时继续分页查询,false 时直接返回
                    if (!dialect.afterCount(count, parameter, rowBounds)) {
                        //当查询总数为 0 时,直接返回空的结果
                        return dialect.afterPage(new ArrayList(), parameter, rowBounds);
                    }
                }
                //判断是否需要进行分页查询
                if (dialect.beforePage(ms, parameter, rowBounds)) {
                    //生成分页的缓存 key
                    CacheKey pageKey = cacheKey;
                    //处理参数对象
                    parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey);
                    //调用方言获取分页 sql
                    String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey);
                    BoundSql pageBoundSql = new BoundSql(configuration, pageSql, boundSql.getParameterMappings(), parameter);
                    //设置动态参数
                    for (String key : additionalParameters.keySet()) {
                        pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
                    }
                    //执行分页查询
                    resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql);
                } else {
                    //不执行分页的情况下,也不执行内存分页
                    resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);
                }
            } else {
                //rowBounds用参数值,不使用分页插件处理时,仍然支持默认的内存分页
                resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
            }
            return dialect.afterPage(resultList, parameter, rowBounds);
        } finally {
            dialect.afterAll();
        }
    }

    /**
     * 执行手动设置的 count 查询,该查询支持的参数必须和被分页的方法相同
     *
     * @param executor
     * @param countMs
     * @param parameter
     * @param boundSql
     * @param resultHandler
     * @return
     * @throws IllegalAccessException
     * @throws SQLException
     */
    private Long executeManualCount(Executor executor, MappedStatement countMs,
                                   Object parameter, BoundSql boundSql,
                                   ResultHandler resultHandler) throws IllegalAccessException, SQLException {
        CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql);
        BoundSql countBoundSql = countMs.getBoundSql(parameter);
        Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);
        Long count = ((Number) ((List) countResultList).get(0)).longValue();
        return count;
    }

    /**
     * 执行自动生成的 count 查询
     *
     * @param executor
     * @param countMs
     * @param parameter
     * @param boundSql
     * @param rowBounds
     * @param resultHandler
     * @return
     * @throws IllegalAccessException
     * @throws SQLException
     */
    private Long executeAutoCount(Executor executor, MappedStatement countMs,
                                   Object parameter, BoundSql boundSql,
                                   RowBounds rowBounds, ResultHandler resultHandler) throws IllegalAccessException, SQLException {
        Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
        //创建 count 查询的缓存 key
        CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql);
        //调用方言获取 count sql
        String countSql = dialect.getCountSql(countMs, boundSql, parameter, rowBounds, countKey);
        //countKey.update(countSql);
        BoundSql countBoundSql = new BoundSql(countMs.getConfiguration(), countSql, boundSql.getParameterMappings(), parameter);
        //当使用动态 SQL 时,可能会产生临时的参数,这些参数需要手动设置到新的 BoundSql 中
        for (String key : additionalParameters.keySet()) {
            countBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
        }
        //执行 count 查询
        Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);
        Long count = (Long) ((List) countResultList).get(0);
        return count;
    }

    /**
     * 尝试获取已经存在的在 MS,提供对手写count和page的支持
     *
     * @param configuration
     * @param msId
     * @return
     */
    private MappedStatement getExistedMappedStatement(Configuration configuration, String msId){
        MappedStatement mappedStatement = null;
        try {
            mappedStatement = configuration.getMappedStatement(msId, false);
        } catch (Throwable t){
            //ignore
        }
        return mappedStatement;
    }

    @Override
    public Object plugin(Object target) {
        //TODO Spring bean 方式配置时,如果没有配置属性就不会执行下面的 setProperties 方法,就不会初始化,因此考虑在这个方法中做一次判断和初始化
        //TODO https://github.com/pagehelper/Mybatis-PageHelper/issues/26
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        //缓存 count ms
        msCountMap = CacheFactory.createCache(properties.getProperty("msCountCache"), "ms", properties);
        String dialectClass = properties.getProperty("dialect");
        if (StringUtil.isEmpty(dialectClass)) {
            dialectClass = default_dialect_class;
        }
        try {
            Class<?> aClass = Class.forName(dialectClass);
            dialect = (Dialect) aClass.newInstance();
        } catch (Exception e) {
            throw new PageException(e);
        }
        dialect.setProperties(properties);

        String countSuffix = properties.getProperty("countSuffix");
        if (StringUtil.isNotEmpty(countSuffix)) {
            this.countSuffix = countSuffix;
        }

        try {
            //反射获取 BoundSql 中的 additionalParameters 属性
            additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters");
            additionalParametersField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            throw new PageException(e);
        }
    }

}


接下来是dao层接口:public List<Admin> selectAdminAll(Admin data);

然后mapper文件里的SQL语句为:

	<select id="selectAdminAll"  resultType="com.zih.po.Admin">
		select * from admin 
	</select>

service接口如同dao层接口:public List<Admin> selectAdminAll(Admin data);

我有点不太理解这样写的含义,这个service里面的接口跟dao层接口是相同的,有人给我说这样是为了降低耦合,但是我还是不太理解这样写的好处,好像是在重复,但是对于初学者来说,讲究那么多干嘛。。。。。。。(想弄懂,但是我太菜了。。。)

程序猿压力大吗???不大!!复制粘贴!!! 能跑就行!!! 能有什么压力!!!! 是吧、、、、

好了回归正题,接着来!

service实现类:

@Service("AdminService")
public class AdminServiceImpl implements AdminService{
	//注入AdminDao
	@Autowired
	private AdminDao adminDao;

	// 查询管理员列表
	public List<Admin> selectAllAdmin(Admin admin) {
		return adminDao.selectAdminAll(admin);
	}
}

前面基本上是分不分页没什么区别,区别就是加了一个拦截器Pageinterceptor,改了一下mybatis配置文件而已

下面是controller类:

@RequestMapping("/query")
	public String AdminQuery(@RequestParam(required = false,defaultValue = "1",value = "pn")Integer pn,ModelMap map,String adminId,String adminName,HttpServletRequest req){

		
			//这里采用总子账号的权限,根据admin的公司实现,本公司的账号只能看到本公司的管理员账号
			Admin currentAdmin=(Admin) req.getSession().getAttribute("admin");
			Admin admin = new Admin();
			admin.setAdminId(adminId);
			admin.setAdminName(adminName);
			admin.setAdminCompany(currentAdmin.getAdminCompany());
			
			//========下面三句才是分页查询的关键=========
			
			//引入分页查询,使用PageHelper分页功能
	        //在查询之前传入当前页,然后多少记录
	        PageHelper.startPage(pn,10);
	        //startPage后紧跟的这个查询就是分页查询
			List<Admin> adminList = adminService.selectAllAdmin(admin);
			//使用PageInfo包装查询结果,只需要将pageInfo交给页面就可以
	        PageInfo pageInfo = new PageInfo<>(adminList,10);
	        //pageINfo封装了分页的详细信息,也可以指定连续显示的页数
	        map.put("pageInfo", pageInfo);
			
			System.out.println("查询管理员数目"+ adminList.size());
		
			return "admin/queryAdmin";
	}

这里queryAdmin.jsp,使用bootstrap框架,注意上文controller里面map返回的是pageInfo,因此页面取参的时候,应该使用pageInfo.adminList文件的内容为:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://"
			+ request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

<title>无标题文档</title>
<base href="<%=basePath%>" />
<script type="text/javascript" src="<%=basePath%>/js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.idTabs.min.js"></script>
<link href="css/style.css" rel="stylesheet" type="text/css" />
<!-- <script type="text/javascript" src="editor/kindeditor.js"></script> -->

<!-- Bootstrap Core CSS -->
<script type="text/javascript" src="<%=basePath%>/js/bootstrap.min.js"></script>
<link href="<%=basePath%>/css/bootstrap.min.css" rel="stylesheet" />

<style type="text/css">
#navbar {
	width: 85px;
	height: 35px;
	background: url('images/btnbg.png') no-repeat center;
	font-size: 14px;
	font-weight: bold;
	color: #fff;
	cursor: pointer;
	border-radius: 3px;
	behavior: url(js/pie.htc);
	display: inline-block;
	vertical-align: middle;
	text-align: center;
	line-height: 33px;
	position: relative;
	margin-bottom: 3px;
}
</style>
<script type="text/javascript">
	$("#usual1 ul").idTabs();
	$('.tablelist tbody tr:odd').addClass('odd');
</script>
<script type="text/javascript">
	function checkedValue() {
		var chk_value = [];
		if (!confirm("确定要删除吗?"))
			return;
		$('input[name="test"]:checked').each(function() {
			chk_value.push($(this).val());
		});
		$("#bindValues").val(chk_value);
		$("#delete").click();
	}

	function checkbox() {
		var allselect = document.getElementById("allselect");
		var selects = document.getElementsByName("test");
		if (allselect.checked) {
			for ( var i = 0; i < selects.length; i++) {
				selects[i].checked = true;
			}
		} else {
			for ( var i = 0; i < selects.length; i++) {
				selects[i].checked = false;
			}
		}
	}
</script>
</head>

<body>
	<div class="formbody">
		<div class="place">
			<span>位置:</span>
			<ul class="placeul">
				<li>基础资料</li>
				<li>操作员信息</li>
			</ul>
		</div>
		<div id="tab2" class="tabson">
			<form action="admin/query.do" method="post">
				<div class="seachform">
					<label>用户账号:</label>
					<input id="adminId" name="adminId" type="text" value="${re_adminId}" class="scinput" />
					<label>用户姓名:</label>
					<input id="adminName" name="adminName" type="text" value="${adminName}" class="scinput" />
					<input type="submit" class="scbtn" value="查询" />
					<label>&nbsp;</label> 
					<input name="" type="button" class="scbtn" value="删除" onclick="checkedValue()" />
					<label>&nbsp;</label> 
					<a href="admin/new.do" id="navbar" type="button" class="scbtn">新增用户</a>
				</div>
			</form>
			<table class="tablelist" align="center">
				<tr>
					<th>全选&nbsp;&nbsp; <input type="checkbox" name="allselect"
						id="allselect" onclick="checkbox()">
					</th>
					<th>账户</th>
					<th>姓名</th>
					<th>角色</th>
					<th>更新</th>
					<th>更新时间</th>
					<th>创建</th>
					<th>创建时间</th>
					<th width="8%">操作</th>
				</tr>
				<c:forEach items="${pageInfo.list}" var="sa">
					<tr align="center">
						<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input
							name="test" type="checkbox" value="${sa.adminNum }" /></td>
						<td>${sa.adminId }</td>
						<td>${sa.adminName }</td>
						<td>${sa.adminRole }</td>
						<td>${sa.updateAdmin }</td>
						<td><fmt:formatDate value="${sa.updateDateTime }" type="both"
								pattern="yyyy-MM-dd HH:mm:ss" /></td>
						<td>${sa.createAdmin }</td>
						<td><fmt:formatDate value="${sa.createDateTime }" type="both"
								pattern="yyyy-MM-dd HH:mm:ss" /></td>
						<td style="vertical-align:middle; text-align:center;"><a
							class="tablelink" href="admin/${sa.adminId}/edit.do">修改</a></td>
					</tr>
				</c:forEach>

			</table>
		
			<form action="admin/delete.do" method="post">
				<input type="hidden" id="bindValues" name="bindValues" value="" />
				<div style="visibility: hidden;">
					<input type="submit" class="scbtn" value="删除" id="delete" />
				</div>
			</form>
			<script type="text/javascript">
				$("#usual1 ul").idTabs();
				$('.tablelist tbody tr:odd').addClass('odd');
			</script>
		</div>
	</div>


	<!--显示分页信息-->
	<div class="row">
		<!--文字信息-->
		<div class="col-md-11 text-right">当前第 ${pageInfo.pageNum}.总共
			${pageInfo.pages}.一共 ${pageInfo.total} 条记录</div>

		<!--点击分页-->
		<div class="col-md-11 text-right">
			<nav aria-label="Page navigation">
			<ul class="pagination">

				<li><a class="paging" href="admin/query.do?pn=1">首页</a>
				</li>

				<!--上一页-->
				<li><c:if test="${pageInfo.hasPreviousPage}">
						<a class="paging"
							href="admin/query.do?pn=${pageInfo.pageNum-1}"
							aria-label="Previous"> <span aria-hidden="true">«</span> </a>
					</c:if></li>

				<!--循环遍历连续显示的页面,若是当前页就高亮显示,并且没有链接-->
				<c:forEach items="${pageInfo.navigatepageNums}" var="page_num">
					<c:if test="${page_num == pageInfo.pageNum}">
						<li class="active"><a href="javascript:void(0)">${page_num}</a>
						</li>
					</c:if>
				</c:forEach>

				<!--下一页-->
				<li><c:if test="${pageInfo.hasNextPage}">
						<a  class="paging"
							href="admin/query.do?pn=${pageInfo.pageNum+1}"
							aria-label="Next"> <span aria-hidden="true">»</span> </a>
					</c:if></li>

				<li><a id="endPage" class="paging"
					href="admin/query.do?pn=${pageInfo.pages}">尾页</a>
				</li>
			</ul>
			</nav>
		</div>

	</div>
<script type="text/javascript">
    $(function(){
        var adminName = $("#adminName").val();
        var adminId = $("#adminId").val();
        $("a.paging").click(function(){
            var href = this.href + "&adminName=" + adminName + "&adminId=" + adminId;
            window.location.href = href;
            return false; 
        }); 
    })
</script>

</body>
</html>

分页效果图:
这里写图片描述

需要引用的样式:链接: https://pan.baidu.com/s/1TMwNpNco3yw9nSg9GMfAQA 提取码: 2jss

到这里分页就算完成了,关键在于controller里面的三行代码,使用起来是相当的简洁,但是页面存在一点小bug,目前就是这样了,以后有解决办法了再更新!

其中翻页之后 条件查询丢失的bug:需要在controller里面添加返回值才可以
在这里插入图片描述
这里不直接返回adminId是因为,我这里直接把登录之后的admin存到session里面了,直接返回adminId的话,翻页之后就覆盖掉页面传过来的的条件了。


解决点击当前页面标号跳转的bug:

之前在分页的页面中,由于jsp页面中的对应超链接里面,当前页面标号的href是#,所以会自动跳转到项目的首页去了,这当然不是我们需要的,这里可以将href里面的链接换成这个:javascript:void(0),然后点击当前页面标号,就不会跳转到空的页面了。
这里写图片描述

PageHelpe开源地址

github项目地址:https://github.com/pagehelper/Mybatis-PageHelper
码云 项目地址:http://git.oschina.net/free/Mybatis_PageHelper


记录遇到的一个bug:
在xml文件中的查询语句中:关于查询的返回类型,我记得resultMap="BaseResultMap"跟resultType=“实体类的绝对路径”效果是一样的,但是今天这样写了之后,返现返回的list数据,都是null,很费解,改了半天才找到这里

  <select id="findAccountList" parameterType="java.lang.Integer" resultMap="BaseResultMap">
  	select * from account where user_id = #{userId,jdbcType=INTEGER}
  </select>
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页