本文记录第一次使用Mybatis时碰到的一些错误和简单理解,采用的示例是Eclipse中的JAVA工程,采用XML文件定义数据库连接。

可以使用Java JDBC API直接操作数据库,但使用框架会更便捷、高效而且还可以利用框架提供的某些强大的功能(比如事务管理),而Mybatis就是这样的一个框架。

Mybatis主要由四大部分组成:

①SqlSessionFactoryBuilder

②SqlSessionFactory

③SqlSession

④SQL Mapper

要想访问(操作)数据库:要建立数据库连接,要定义数据库操作方法(insert/update/delete...),要有具体的操作数据库中的表 的SQL语句,而SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession就是用来负责底层建立数据库连接、管理连接、释放连接等。对于业务层而言,关心的是:定义一个SQL语句,让Mybatis方便地把SQL语句执行后的结果 呈现给使用者,而这可以通过SQL Mapper来完成。

SQL Mapper由两部分组成,一是:JAVA 接口,该接口中定义了 业务层 要对数据库进行何种操作;另一部分是:XML配置文件,定义了具体的数据库操作语句和映射规则。

假设要操作数据库test中的表 t_role,t_role有三个字段:id ,role_name,和 note

+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| role_name | varchar(20) | YES | | NULL | |
| note | varchar(20) | YES | | NULL | |
+-----------+-------------+------+-----+---------+----------------+

该表对应的POJO类如下:

package chapter2.pojo;

public class Role {
private Long id;
private String roleName;
private String note;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
} @Override
public String toString() {
return "id:" + id + ", roleName:" + roleName + ", note:" + note;
}
}

JAVA接口中定义的一些操作如下:

package chapter2.mapper;
import java.util.List;
import java.util.Map;
import chapter2.pojo.Role; public interface RoleMapper {
public Role getRole(Long id);
public int deleteRole(Long id);
public int insertRole(Role role);
public List<Role> findRoleByMap(Map<String, String> params);
}

与该接口对应,定义的具体操作数据库的配置文件RoleMapper.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"> <mapper namespace="chapter2.mapper.RoleMapper"> <resultMap type="chapter2.pojo.Role" id="roleMap">
<id property="id" column="id"/><!-- primary key -->
<result property="roleName" column="role_name"/><!-- 普通列的映射关系 -->
<result property="note" column="note"/>
</resultMap> <select id="getRole" parameterType="long" resultType="Role">
select id, role_name as roleName, note from t_role where id = #{id}
</select>
<insert id="insertRole" parameterType="Role">
insert into t_role(role_name,note) values(#{roleName},#{note})
</insert>
<delete id="deleteRole" parameterType="long">
delete from t_role where id = #{id}
</delete> <select id="findRoleByMap" parameterType="map" resultMap="roleMap">
select id,role_name,note from t_role
where role_name like concat('%', #{roleName},'%')
and note like concat('%',#{note},'%')
</select>
</mapper>

然后,就可以用SqlSessionFactory创建SqlSession,SqlSession获取相应的RoleMapper实例,再使用RoleMapper实例调用RoleMapper接口中定义的方法,最终由Mybatis根据 RoleMapper.xml配置文件将 方法 与 映射成具体的数据库操作语句,最终访问数据库。

使用SqlSessionFactoryBuilder 根据 mybatisConfig.xml中配置的 dataSource创建SqlSessionFactory,再使用SqlSessionFactory创建SqlSession,代码如下:

package chapter2.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger; import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class SqlSessionFactoryUtil {
private static SqlSessionFactory sqlSessionFactory = null;
private static final Class CLASS_LOCK = SqlSessionFactoryUtil.class;
private SqlSessionFactoryUtil() {} public static SqlSessionFactory initSqlSessionFactory() {
String resource = "mybatisConfig.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
}catch(IOException ex) {
Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE, null, ex);
}
synchronized (CLASS_LOCK) {
if(sqlSessionFactory == null) {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
}
return sqlSessionFactory;
} public static SqlSession openSqlSession() {
if(sqlSessionFactory == null)
{
initSqlSessionFactory();
}
return sqlSessionFactory.openSession();
}
}

报错:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in 
class path resource [detect/xx/xx/applicationContext.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException:
Failed to parse config resource: class path resource [detect/xx/xx/mybatisConfig.xml]; nested exception is org.apache.ibatis.builder.BuilderException:
Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance.
Cause: org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 142; 元素内容必须由格式正确的字符数据或标记组成。

从上面错误可看出,若不能正确地创建sqlSessionFactory,有可能是 mybatisConfig.xml配置有错,而 mybatisConfig.xml里面 通过 <mapper>标签指定了 xxxMapper.xml SQL Mapper Configuration。

因此,也要检查 xxxMapper.xml 中写的 SQL 语句 是否正确

用户程序根据SqlSession来获取RoleMapper(第20行),然后调用里面定义的方法操作数据库,从这里也可以看出,我们只需要定义好接口,在XML配置文件中定义SQL操作语句,就可以访问数据库了:代码如下:

package chapter2.main;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.apache.ibatis.session.SqlSession; import chapter2.mapper.RoleMapper;
import chapter2.pojo.Role;
import chapter2.util.SqlSessionFactoryUtil; public class Chapter2Main {
public static void main(String[] args)throws IOException {
SqlSession sqlSession = null; try {
sqlSession = SqlSessionFactoryUtil.openSqlSession();
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); Role role = new Role();
role.setRoleName("testName");
role.setNote("testNote");
roleMapper.insertRole(role);
//roleMapper.deleteRole(1L);
sqlSession.commit(); Map<String, String> paramsMap = new HashMap<>();
paramsMap.put("roleName", "me");
paramsMap.put("note", "no");//与sql语句中的 #{note} #{roleName}一致
List<Role> result = roleMapper.findRoleByMap(paramsMap);
for (Role role2 : result) {
System.out.println(role2);
} }catch(Exception e) {
System.out.println(e);
sqlSession.rollback();
}finally {
if(sqlSession != null)
sqlSession.close();
} }
}

Mybatis配置数据库连接: mybatisConfig.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>
<properties resource="jdbc.properties">
</properties>
<typeAliases>
<typeAlias alias="Role" type="chapter2.pojo.Role" />
</typeAliases> <environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="autoCommit" value="false" />
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments> <mappers>
<mapper resource="chapter2\mapper\RoleMapper.xml" />
</mappers>
</configuration>

Mybatis的XML配置文件定义了许多配置标签:比如 <configuration> <properties> <settings> <typeAliases> ....等标签。

这些标签是有层次结构的,顺序不能乱。比如,<properties>标签应该放在 <typeAliases> 标签前面。

上面的第5行<properties>标签 通过  resource 指定一个外部jdbc配置文件,这样在16-21行配置 数据源 的时候,就可以使用 变量 来引用 外部jdbc配置文件中定义的值了,从而方便切换数据库配置。

外部jdbc配置文件如下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=xxxx

下面来重点解释:操作数据库的XML配置文件RoleMapper.xml 和 接口RoleMapper 以及POJO类RoleMapper之间的一些关系:

RoleMapper 接口中定义的getRole方法:

public Role getRole(Long id);

RoleMapper.xml配置文件中与该方法对应的SQL语句:

    <select id="getRole" parameterType="long" resultType="Role">
select id, role_name as roleName, note from t_role where id = #{id}
</select>

id 用来唯一标明这条 select 语句。它与RoleMapper.xml中 <mapper namespace>标签内容组合在一起,唯一标识了 这条 select 操作语句。这里的resultType="Role","Role"是在mybatisConfig.xml中定义的别名。

<mapper namespace="chapter2.mapper.RoleMapper">

public Role getRole(Long id);

<select id="getRole" parameterType="long" resultType="Role">

id 的值getRole 就是接口RoleMapper中 定义的 getRole方法名
parameterType 就是getRole方法的参数类型
resultType 就是执行SQL语句后返回的结果,把结果 封装 成POJO类 Role 类型---这也是getRole方法的返回类型。而方法的参数 会传递给#{id}

几种传 多个参数 给SQL语句的方法:

一,通过Map对象传参数

RoleMapper中定义的findRoleByMap方法

    public List<Role> findRoleByMap(Map<String, String> params);
    <select id="findRoleByMap" parameterType="map" resultMap="roleMap">
select id,role_name,note from t_role
where role_name like concat('%', #{roleName},'%')
and note like concat('%',#{note},'%')
</select>

当我们需要根据多个 参数 查找数据库时,且查找的结果也可能返回多条记录时,就使用上面的配置。

paramterType="map",传入一个map对象作为select语句的参数,其中map中的每个元素的key 对应 while子句中的#{roleName},#{note}

由于这里的while子句 只根据 两个参数 来查询,因此map的长度为2. 而map的value,则是 查询的条件的值。

            Map<String, String> paramsMap = new HashMap<>();
paramsMap.put("roleName", "me");//value是要满足的条件值 while note = "me"
paramsMap.put("note", "no");//Key与sql语句中的 #{note} #{roleName}一致
List<Role> result = roleMapper.findRoleByMap(paramsMap);

select id,role_name,note from t_role   where role_name like concat('%', ?,'%')   and note like concat('%',?,'%')

比如:select id,role_name,note from t_role   where role_name like concat("me")   and note like concat("no")

resultMap指明了返回的“结果”的形式:resultMap=roleMap。resultMap的定义如下:(可理解为:resultMap的key是 属性名或者字段名,而value则是 相应的 结果值)

<resultMap type="chapter2.pojo.Role" id="roleMap">
<id property="id" column="id"/><!-- primary key -->
<result property="roleName" column="role_name"/><!-- 普通列的映射关系 -->
<result property="note" column="note"/>
</resultMap>

<id property="id" column="id" 表明 id 是 t_role表的主键,主键的列名是 "id"

<result property="roleName" colum="role_name"/> 表明:roleName是POJO类的属性名,"role_name"是数据库表t_role的列名,将二者对应起来。

二,使用参数注解的方式传递多个参数

或者使用更“易懂“的映射方法:----参数注解

RoleMapper接口里面定义的方法:

    public List<Role> findRoleByAnnotation(@Param("roleName")String roleName, @Param("note")String note);

RoleMapper.xml配置文件里面的定义的SQL语句:这里就没有 paramterType 来定义查询的参数了

        <select id="findRoleByAnnotation"resultMap="roleMap">
select id,role_name,note from t_role
where role_name like concat('%', #{roleName},'%')
and note like concat('%',#{note},'%')
</select>

客户端 调用方法:这里,就可以不用HashMap封装多个待查询的参数了。

List<Role> res = roleMapper.findRoleByAnnotation("me", "no");
for (Role role2 : res) {
System.out.println(role2);
}

三,使用JAVA Bean对象传递参数:

RoleMapper.xml配置文件里面的定义的SQL语句:

    <select id="findRoleByParam" parameterType="chapter2.pojo.RoleParam"
resultMap="roleMap">
select id,role_name,note from t_role
where role_name like
concat('%', #{roleName},'%')
and note like concat('%',#{note},'%')
</select>

RoleMapper.java接口方法:

    public List<Role> findRoleByParam(RoleParam role);

客户端调用执行:

            RoleParam rp = new RoleParam();
rp.setNote("note");
rp.setRoleName("test");
List<Role> roles = roleMapper.findRoleByParam(rp);

批量插入操作:

RoleMapper.xml配置文件里面的定义的SQL语句:

    <insert id="insertBatch"  useGeneratedKeys="true" parameterType="java.util.List">
insert into t_role(role_name, note)
values
<foreach collection="list" item="item" index="index"
separator=",">
(#{item.roleName},#{item.note})
</foreach>
</insert>

useGeneratedKeys="true" 表明使用数据库表中自带的主键自增策略。在文章所述的t_role表的结构中, id 是自增的主键,但是这里的批量插入操作,并不需要显示的插入 id 的值。

待插入的每条记录值 放在 java.util.List 对象中保存,通过 foreach 循环遍历,"item"代表遍历到的每条记录---即每个Role对象, 通过 #{item.roleName} 和 #{item.note} 取出Role对象属性值---即每个表的字段值。

RoleMapper.java接口方法:

    public void insertBatch(List<Role> roleList);

客户端调用执行:(记得最终 调用 commit() 方法进行提交)

            sqlSession = SqlSessionFactoryUtil.openSqlSession();
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); Role role = new Role();
role.setRoleName("testName");
role.setNote("testNote"); Role role2 = new Role();
role2.setRoleName("xx");
role2.setNote("notexx"); List<Role> roleList = new ArrayList<>();
roleList.add(role2);
roleList.add(role2); roleMapper.insertBatch(roleList);
System.out.println("insert finished");
sqlSession.commit();

MyBatis简单使用和入门理解的更多相关文章

  1. MyBatis运行流程及入门第一个程序

    1. mybatis是什么? MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并 ...

  2. 动态规划初级 入门理解 C#代码

      using System; using System.Collections.Generic; using System.Linq; using System.Text; using Micros ...

  3. MyBatis简单使用方式总结

    MyBatis简单使用方式总结 三个部分来理解: 1.对MyBatis的配置部分 2.实体类与映射文件部分 3.使用部分 对MyBatis的配置部分: 1.配置用log4J显式日志 2.导入包的别名 ...

  4. SSM框架之Mybatis(1)入门

    Mybatis(1)入门 1.mybatis的概述 mybatis是一个持久层框架,用java编写的. 它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等 ...

  5. 浅析MyBatis(二):手写一个自己的MyBatis简单框架

    在上一篇文章中,我们由一个快速案例剖析了 MyBatis 的整体架构与整体运行流程,在本篇文章中笔者会根据 MyBatis 的运行流程手写一个自定义 MyBatis 简单框架,在实践中加深对 MyBa ...

  6. 用一个简单的例子来理解python高阶函数

    ============================ 用一个简单的例子来理解python高阶函数 ============================ 最近在用mailx发送邮件, 写法大致如 ...

  7. 一个简单的iBatis入门例子

    一个简单的iBatis入门例子,用ORACLE和Java测试 目录结构: 1.导入iBatis和oracle驱动. 2.创建类Person.java package com.ibeats;import ...

  8. MyBatis简单的增删改查以及简单的分页查询实现

    MyBatis简单的增删改查以及简单的分页查询实现 <? xml version="1.0" encoding="UTF-8"? > <!DO ...

  9. spring+springMVC+mybatis简单整合

    spring+springMVC+mybatis简单整合, springMVC框架是spring的子项目,所以框架的整合方式为,spring+Mybatis或springMVC+mybatis. 三大 ...

随机推荐

  1. configure: error: no acceptable C compiler found in $PATH 问题解决

    解决办法: 安装GCC软件套件 [root@localhost ~]# yum install gccLoaded plugins: fastestmirrorLoading mirror speed ...

  2. Linux添加新硬盘及分区,格式化,挂载

    1.查看分区信息: [root@localhost /]# fdisk -l Disk /dev/vdb: 209.7 GB, 209715200000 bytes16 heads, 63 secto ...

  3. SpringBoot构建大数据开发框架

    http://blog.51cto.com/yixianwei/2047886 为什么使用SpringBoot 1.web工程分层设计,表现层.业务逻辑层.持久层,按照技术职能分为这几个内聚的部分,从 ...

  4. 洛谷P3723 礼物

    以前看到过,但是搞不倒.知道了算法之后就好搞了. 题意:给定两个长为n的序列,你可以把某个序列全部加上某个数c,变成循环同构序列. 求你操作后的min∑(ai - bi)² 解: 设加上的数为c,那么 ...

  5. android studio adb.exe已停止工作(全面成功版 进程的查询和开启)

    先输入adb看是否存在. 如果不存在则:在系统path里添加C:\Users\nubia\AppData\Local\Android\sdk\platform-tools 因为这个目录里有adb 或者 ...

  6. python基础四-文件读取

    文件读取 open()接受一个参数:要打开的文件名, 并返回一个表示文件的对象, 存储到后面的变量中 python会在当前执行文件所在目录查找 可以使用绝对路径, 在linux中使用'/', 在win ...

  7. 4.2、LED1、LED2交替闪烁

    #include "ioCC2530.h" //引用CC2530头文件 /***************************************************** ...

  8. HTML学习笔记Day4

    一.浮动属性 1.首先要知道,div是块级元素,在页面中独占一行,自上而下排列,也就是传说中的流: 无论多么复杂的布局,其基本出发点均是:“如何在一行显示多个div元素”: 显然标准流已经无法满足需求 ...

  9. mysql优化好文

    https://segmentfault.com/a/1190000006158186

  10. 如何修改const常量值

    总结:这个跟计算机语言类别和编译器有关,本文是在linux环境下说明的. 分两种情况: 1. C语言: 2. C++语言: /*! * \Description: * \author scictor ...