一、MyBatis安装:
https://github.com/mybatis/mybatis-3/releases
下载mybatis-3.4.6.zip,解压将mybatis-3.4.6.jar包放到WEB-INF/lib目录下
二、编写核心配置文件Configuration.xml:
下载Source code(zip)并解压
将mybatis-3-mybatis-3.4.6/src/test/java/org/apache/ibatis/submitted/complex_property/目录下的
Configuration.xml模板文件拷贝到项目com.maple.config包中,修改如下:
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/demo"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
注释掉<settings><typeAliases>标签
三、MyBatis向Dao层提供的重要对象:SqlSession,
SqlSession的作用如下:
1、向SQL语句传入参数
2、执行SQL语句
3、获取执行SQL语句的结果
4、事务的控制
如何获得SqlSession,分三步:
1、通过核心配置文件获取数据库连接相关信息
2、通过配置信息构建SqlSessionFactory对象
3、通过SqlSessionFactory打开数据库会话(SqlSession:与根数据库交互的会话)
获得SqlSession的实现方法:
建立com.maple.db.DBAccess类【用于得到SqlSession】:
public SqlSession getSqlSession() throws IOException {
// 通过配置文件获取数据库连接信息
Reader reader = Resources.getResourceAsReader("com/maple/config/Configuration.xml");
// 通过配置信息构建一个SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
// 通过SqlSessionFactory打开一个数据库会话
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
总结:如此一来,dao层的工作就被简化,不再借助Connection,PrepareStatement和ResultSet等手动方式完成
转而通过sqlSession对象读配置文件的方式操作数据库
四、用MyBatis实现数据库查询操作
1、新建Message.xml子配置文件
下载Source code(zip)并解压
将mybatis-3-mybatis-3.4.6/src/test/java/org/apache/ibatis/submitted/complex_property/目录下的
User.xml模板文件拷贝到项目com.maple.config.sqlxml包中,命名为Message.xml,并修改如下:
<mapper namespace="Message">
<resultMap type="com.maple.bean.Message" id="MessageResult">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="command" jdbcType="VARCHAR" property="command"/>
<result column="description" jdbcType="VARCHAR" property="description"/>
<result column="content" jdbcType="VARCHAR" property="content"/>
</resultMap>
<select id="queryMessageList" parameterType="com.maple.bean.Message" resultMap="MessageResult">
select id,command,description,content from message where 1=1
<if test="command!=null and !"".equals(command.trim())">and command=#{command}</if>
<if test="description!=null and !"".equals(description.trim())">and description like '%' #{description} '%'</if>
</select>
</mapper>
说明:
a、mapper标签的namespace名空间是为了保证与其它配置文件命名重名不冲突,而且必须填写
b、select标签的id属性必须唯一,供SqlSession对象使用,
parameterType属性表示传递的参数类型(必须带包名,lang包除外),配置文件中只能接收一个参数
resultMap属性用于指定存放查询结果的resultMap标签的id值
c、resultMap标签用于接收select查找的结果,其type属性用于指定结果集的存储类型(必须带包名,lang包除外)
d、resultMap标签下的子标签有两种:<id>与<result>分别用于指定结果集中的主键和其它列,子标签的属性含义都相同
e、子标签中的column属性表示在数据库中查询到的列名,jdbcType属性表示该列在数据库中的类型
property属性表示该列对应存储在结果集中(一般是JavaBean)的属性名
f、查询语句中可包含查询条件:可使用<if>或<foreach>标签,并且支持OGNL表达式(不支持EL表达式)
<if test="">sql expression</if>
<foreach collection="" index="" item="" separator="">sql expression</foreach>
g、具体OGNL取值方法可参考图例,test属性中支持调用java方法
h、注意遇到双引号要用"代替,遇到&&要用&&代替或用and代替,原来sql子表达式中的问号要用#{}写法替换
i、原子表达式前面的空格可忽略,配置文件会自动帮忙完成
2、在核心配置文件中加入子配置文件的映射关系
<mappers>
<mapper resource="com/maple/config/sqlxml/Message.xml"/>
</mappers>
说明:子配置文件的路径从src目录开始
3、在dao层用SqlSession对象实现数据库查询操作
public List<Message> queryMessageList(String command,String description){
SqlSession sqlSession = null;
List<Message> messageList = null;
// org.apache.ibatis.logging.LogFactory.useLog4JLogging();
try {
sqlSession = new DBAccess().getSqlSession(); // 打开与数据库交互的会话
Message msg = new Message();
msg.setCommand(command);
msg.setDescription(description);
// 通过sqlSession执行SQL语句
messageList = sqlSession.selectList("Message.queryMessageList",msg);
} catch (IOException e) {
e.printStackTrace();
}finally {
sqlSession.close();
}
return messageList;
}
五、使用Log4j调试动态Sql
1、下载log4j-1.2.17版本的包并拷贝到WEB-INF/lib目录下
2、在src根目录下添加log4j.properties属性配置文件,内容如下:
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%-5p] %t: [%c] %m%n
log4j.logger.org.apache=INFO
说明:
a、其中rootLogger表示根目录下的日志,也可记录其它包下的日志,如org.apache包
b、DEBUG表示日志输出级别,共4级,分别是debug,info,warn,error(由低到高)
c、stdout表示日志输出位置,可指定输出的布局和参数
%d产生日志的时间,
%t是产生日志所处的线程名称,
%-5p输出日志的级别,将占5位字符,不足5位用空格填补,-指的是在右边补齐,
%c你输出日志的包以及类的全名,
%m是你附加的信息
六、用MyBatis实现数据库单条删除操作
1、修改Message.xml文件,添加如下代码:
<delete id="deleteOneMessage" parameterType="int">
delete from message where id=#{_parameter}
</delete>
2、修改dao层代码:
public void deleteOneMessage(int id) {
SqlSession sqlSession = null;
try {
sqlSession = new DBAccess().getSqlSession(); // 打开与数据库交互的会话
sqlSession.delete("Message.deleteOneMessage",id); // 通过sqlSession执行SQL语句
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
}finally {
sqlSession.close();
}
}
3、修改Maintain.service层代码:
public void deleteOneMessage(String id) {
if(id!=null && !"".equals(id.trim())) {
MessageDao messageDao = new MessageDao();
messageDao.deleteOneMessage(Integer.valueOf(id));
}
}
4、修改DeleteOneServlet层代码:
String id = request.getParameter("msgId");
new MaintainService().deleteOneMessage(id); // 异步到此为止
// 向页面直接跳转(不考虑查询条件)
request.getRequestDispatcher("/List.action").forward(request, response);
// 向页面跳转(考虑查询条件)
String command = request.getParameter("command");
String description = request.getParameter("description");
request.setAttribute("messageList", new ListService().queryMessageList(command,description));
request.getRequestDispatcher("/WEB-INF/jsp/back/list.jsp").forward(request, response);
5、修改jsp代码:
<c:forEach items="${messageList }" var="message" varStatus="status">
<tr <c:if test="${status.index%2!=0 }">style="background-color:#ecf6ee;"</c:if>>
<td><input name="selectId" type="checkbox" value="${message.id }" /></td>
<td>${status.index + 1 }</td>
<td>${message.command }</td>
<td>${message.description }</td>
<td>
<a href="#">修改</a>
<a href="javascript:void(0);" data-id="${message.id }" data-basepath="<%=basePath %>" class="delOne">POST删除(异步)</a>
<a href="${basePath }DeleteOne.action?id=${message.id }">GET删除(同步)</a>
</td>
</tr>
</c:forEach>
6、修改js代码:
$(".delOne").on('click',function(e){
$("#msgId").val($(this).data("id"));
// 异步方式
$.ajax({
url:"DeleteOne.action",
type:"post",
data:$("#mainForm").serialize(),
success:function(){
console.log('删除成功');
$(this).closest('tr').remove();
}.bind(this),
error:function(err){
console.log(err);
}
});
// 非异步方式
$("#mainForm").attr('action',"<%=basePath %>DeleteOne.action");
$("#mainForm").submit();
});
7、说明:jdbc的方式做数据维护操作时,默认:conn.setAutoCommit(true); 而sqlSession方式下需要手动:sqlSession.commit();
七、用MyBatis实现数据库批量删除操作
1、修改Message.xml文件,添加如下代码:
<delete id="deleteBatchMessage" parameterType="java.util.List">
delete from message where id in(<foreach collection="list" index="i" item="item" separator=",">#{item}</foreach>)
</delete>
2、修改dao层代码:
public void deleteBatchMessage(List<Integer> ids) {
SqlSession sqlSession = null;
try {
sqlSession = new DBAccess().getSqlSession(); // 打开与数据库交互的会话
sqlSession.delete("Message.deleteBatchMessage",ids); // 通过sqlSession执行SQL语句
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
}finally {
sqlSession.close();
}
}
3、修改Maintain.service层代码:
public void deleteBatchMessage(String[] ids) {
MessageDao messageDao = new MessageDao();
List<Integer> idList = new ArrayList<Integer>();
for(String id:ids) {
idList.add(Integer.valueOf(id));
}
messageDao.deleteBatchMessage(idList);
}
4、修改DeleteBatchServlet层代码:
String[] ids = request.getParameterValues("selectId");
new MaintainService().deleteBatchMessage(ids);
String command = request.getParameter("command");
String description = request.getParameter("description");
request.setAttribute("messageList", new ListService().queryMessageList(command,description));
request.getRequestDispatcher("/WEB-INF/jsp/back/list.jsp").forward(request, response);
5、修改jsp代码:
<c:forEach items="${messageList }" var="message" varStatus="status">
<tr <c:if test="${status.index%2!=0 }">style="background-color:#ecf6ee;"</c:if>>
<td><input name="selectId" type="checkbox" value="${message.id }" /></td>
<td>${status.index + 1 }</td>
<td>${message.command }</td>
<td>${message.description }</td>
<td>
<a href="#">修改</a>
<a href="javascript:void(0);" data-id="${message.id }" data-basepath="<%=basePath %>" class="delOne">POST删除(异步)</a>
<a href="${basePath }DeleteOne.action?id=${message.id }">GET删除(同步)</a>
</td>
</tr>
</c:forEach>
6、修改js代码:
$("#delBatch").on('click',function(e){
e.preventDefault();
$("#mainForm").attr("action",$(this).data("basepath")+"DeleteBatch.action");
$("#mainForm").submit();
});
八、自动回复功能实现
1、异步请求:发送提交命令字段
$.ajax({
url : $("#basePath").val() + "AutoReplyServlet.action",
type : "POST",
dataType : "text",
timeout : 10000,
success : function (data) {
appendDialog("talk_recordboxme","My账号",content);
appendDialog("talk_recordbox","公众号",data);
$("#content").val("");
render();
},
data : {"content":content}
});
2、servlet层接受并处理异步请求
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter out = resp.getWriter();
QueryService queryService = new QueryService();
out.write(queryService.queryByCommand(req.getParameter("content")));
out.flush();
out.close();
}
3、调用service层处理具体业务
public String queryByCommandName(String command) {
MessageDao messageDao = new MessageDao();
List<Message> messageList;
if(Iconst.HELP_COMMAND.equals(command)) {
messageList = messageDao.queryMessageList(null, null);
StringBuilder result = new StringBuilder();
for(int i = 0; i < messageList.size(); i++) {
if(i != 0) {
result.append("<br/>");
}
result.append("回复[" + messageList.get(i).getCommand() + "]可以查看" + messageList.get(i).getDescription());
}
return result.toString();
}
messageList = messageDao.queryMessageList(command,null);
if(messageList.size()>0) {
return messageList.get(0).getContent();
}
return Iconst.NO_MATCHING_CONTENT;
}
4、调用dao层处理具体实现查询(直接调用第四步第3条即可)
九、实现一对多关系的配置
1、新建主表command和子表command_content,并建立相应的实体bean类
其中主表包含子表的集合字段
2、编写数据库xml配置文件
a、新建Command.xml配置文件
<mapper namespace="Command">
<resultMap type="com.imooc.bean.Command" id="Command">
<id column="C_ID" jdbcType="INTEGER" property="id"/>
<result column="NAME" jdbcType="VARCHAR" property="name"/>
<result column="DESCRIPTION" jdbcType="VARCHAR" property="description"/>
<collection resultMap="CommandContent.Content" property="contentList"/>
</resultMap>
<select id="queryCommandList" parameterType="com.imooc.bean.Command" resultMap="Command">
select a.ID C_ID,a.NAME,a.DESCRIPTION,b.ID,b.CONTENT,b.COMMAND_ID
from COMMAND a left join COMMAND_CONTENT b
on a.ID=b.COMMAND_ID
<where>
<if test="name != null and !"".equals(name.trim())">
and a.NAME=#{name}
</if>
<if test="description != null and !"".equals(description.trim())">
and a.DESCRIPTION like '%' #{description} '%'
</if>
</where>
</select>
</mapper>
b、新建CommandContent.xml配置文件
<mapper namespace="CommandContent">
<resultMap type="com.imooc.bean.CommandContent" id="Content">
<id column="ID" jdbcType="INTEGER" property="id"/>
<result column="COMMAND_ID" jdbcType="VARCHAR" property="commandId"/>
<result column="CONTENT" jdbcType="VARCHAR" property="content"/>
</resultMap>
</mapper>
c、总配置文件导入上述两个xml配置文件
<mapper resource="com/imooc/config/sqlxml/Command.xml"/>
<mapper resource="com/imooc/config/sqlxml/CommandContent.xml"/>
3、调用CommandDao层实现数据查询操作
public List<Command> queryCommandList(String name,String description) {
DBAccess dbAccess = new DBAccess();
List<Command> commandList = new ArrayList<Command>();
SqlSession sqlSession = null;
try {
sqlSession = dbAccess.getSqlSession();
Command command = new Command();
command.setName(name);
command.setDescription(description);
// 通过sqlSession执行SQL语句
commandList = sqlSession.selectList("Command.queryCommandList", command);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(sqlSession != null) {
sqlSession.close();
}
}
return commandList;
}
4、调用QueryService层处理业务操作
public String queryByCommand(String name) {
CommandDao commandDao = new CommandDao();
List<Command> commandList;
if(Iconst.HELP_COMMAND.equals(name)) {
commandList = commandDao.queryCommandList(null, null);
StringBuilder result = new StringBuilder();
for(int i = 0; i < commandList.size(); i++) {
if(i != 0) {
result.append("<br/>");
}
result.append("回复[" + commandList.get(i).getName() + "]可以查看" + commandList.get(i).getDescription());
}
return result.toString();
}
commandList = commandDao.queryCommandList(name, null);
if(commandList.size() > 0) {
List<CommandContent> commandContentList = commandList.get(0).getContentList();
int ram = new Random().nextInt(commandContentList.size());
return commandContentList.get(ram).getContent();
}
return Iconst.NO_MATCHING_CONTENT;
}
十、常用标签
1、定义SQL语句
<insert id="" parameterType="">
<delete id="" parameterType="">
<update id="">
<select id="" parameterType="" resultMap="">
2、配置java对象属性与查询结果集中列名(不一定是表字段名)对应关系
<resultMap type="" id="">
<id column="" jdbcType="" property="">
<result column="" jdbcType="" property="">
<collection resultMap="" property="">
<association resultMap="" property="">
</resultMap>
3、格式化标签
<where>:自动判断条件,并去除可能多余的where和and|or关键字
<set>:自动判断更新语句,并去除可能多余的set以及结尾可能多余的逗号
<trim>:可代替<where>或<set>标签
<trim prefix="where" prefixOverrides="and|or">
...
</trim>
<trim prefix="set" suffixOverrides=",">
...
</trim>
4、定义常量<sql>和引用常量<include>标签
<sql id="msgColumns">ID,COMMAND,DESCRIPTION,CONTENT</sql>
select <include refid="msgColumns"/> from MESSAGE
3、控制动态SQL拼接
<if test=""><if>
<foreach collection="" index="" item=""></foreach>
<choose>
<when test="">...</when>
<when test="">...</when>
<otherwise></otherwise>
</choose>
5、配置关联关系:
<collection>:查询主表中结果集中有关联子表的多条数据(一对多)
<collection resultMap="CommandContent.Content" property="contentList"/>
<association>:查询子表中结果集中有关联到主表中的一条数据
<association resultMap="Command.Command" property="command"></association>
十一、常见问题
1、容易混淆的概念:resultMap与resultType
resultMap与resultType都是用来表示结果集中的列与java对象中的属性之间的一种关系,MyBatis帮我们处理结果集,将结果集放到java对象中。
当使用resultMap属性时,还需要单独配置resultMap标签做映射处理
当使用resultMap属性时,还具有通过typeHandler属性来做类型转换的能力(常见于日期或布尔类型)
当使用resultType属性时,就不再需要单独配置resultMap标签了,但要求结果集中的列名与实体类的属性名相同(大小写不敏感)。
当使用resultType属性时,还可以设置为java.util.Map,这时key就是结果集中的列名,value就是结果集中的值(此时列名大小写敏感)
2、容易混淆的概念:parameterType与parameterMap
parameterType指向一个java类型,表示参数类型,与ognl表达式和#{}直接相关
parameterMap需要指向一个用<parameterMap>标签配置的映射关系的id, 用来表示参数中的属性与数据库中的列对应的关系(官方不推荐)
3、#{}与${}与ognl表达式
#{}在sql中会被预编译解析为?,
${}在sql中会被直接解析为原始str,所以还必须加单引号,常用于排序表头字段order by ${}
当parameterType参数类型为String或基本数据类型时,mybatis取值可写为#{任意名},而ognl就必须写成#{_parameter},但为了保持风格统一,mybatis取值也建议写成#{_parameter}
当parameterType参数类型为自定义数据类型Message时,取值只能写为#{属性名}
4、获取自増主键值
<insert id="insertCommandContent" useGeneratedKeys="true" parameterType="com.imooc.bean.Command">
insert into COMMAND(name,description) values(#{name},#{description})
</insert>
上述语句如果想取到插入时的自增主键值,就需要设置useGeneratedKeys="true",由于Command类中有id属性,但是在传入xml中的Command对象里面,其它属性值来自于页面,而id是出于自増的原因,其实是没有值的,因此这时就需要用到另外一个属性keyProperty="id",Mybatis会帮你取新増数据的主键,然后你用keyProperty属性告诉Mybatis将主键存到参数对象中的哪一个属性中(这里属性是id)。这样一来在java代码中,Command对象在传入xml中的时候,id属性是没有值的,等到sqlSession调用配置文件中的sql执行完了以后,id属性就有值了,并且是新増数据的主键值。
5、找不到namespace.id的异常
当总配置表中未加子配置表的映射时,或者调用时命名空间单词拼错,都会抛出“Mapped Statements collection does not contain value for Message.queryMessageList”
6、sql语法排查
利用Log4j将sql语句复制到sql控制台执行一遍,其中?号要替换为查询条件,并加上单引号
7、不要过度使用${}
将mybatis中的sql语句回归到java代码中的方式,叫注解sql,但需要往配置文件中通过判断循环标签去实现动态sql是非常麻烦的
8、乱码问题
a、项目文件本身的编码,通过文件右键属性设为utf-8
b、jsp页面内的编码:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
c、jsp页面传值到servlet后用于转换的编码:
req.setCharacterEncoding("utf-8");
d、用get方式提交中文的话,tomcat里面也要配置中文编码
e、总配置文件中:
<property name="url" value="jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8"/>
f、mysql安装过程中有个配置编码选项选择 Character Set:utf8
g、建数据库时的字符集编码和排序规则编码
h、建表时的字符集编码和排序规则编码
MyBatis学习基础知识小结
猜你喜欢
转载自blog.51cto.com/maplebb/2318531
今日推荐
周排行