本文共 8147 字,大约阅读时间需要 27 分钟。
本文记录第一次使用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类如下:
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 ListfindRoleByMap(Map params);}
与该接口对应,定义的具体操作数据库的配置文件RoleMapper.xml 如下:
insert into t_role(role_name,note) values(#{roleName},#{note}) delete from t_role where id = #{id}
然后,就可以用SqlSessionFactory创建SqlSession,SqlSession获取相应的RoleMapper实例,再使用RoleMapper实例调用RoleMapper接口中定义的方法,最终由Mybatis根据 RoleMapper.xml配置文件将 方法 与 映射成具体的数据库操作语句,最终访问数据库。
使用SqlSessionFactoryBuilder 根据 mybatisConfig.xml中配置的 dataSource创建SqlSessionFactory,再使用SqlSessionFactory创建SqlSession,代码如下:
报错:
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操作语句,就可以访问数据库了:代码如下:
Mybatis配置数据库连接: mybatisConfig.xml
1 2 45 6 78 10 119 12 24 2513 2314 1615 17 2218 19 20 21 26 2827
Mybatis的XML配置文件定义了许多配置标签:比如 <configuration> <properties> <settings> <typeAliases> ....等标签。
这些标签是有层次结构的,顺序不能乱。比如,<properties>标签应该放在 <typeAliases> 标签前面。
上面的第5行<properties>标签 通过 resource 指定一个外部jdbc配置文件,这样在16-21行配置 数据源 的时候,就可以使用 变量 来引用 外部jdbc配置文件中定义的值了,从而方便切换数据库配置。
外部jdbc配置文件如下:
driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/testusername=rootpassword=xxxx
下面来重点解释:操作数据库的XML配置文件RoleMapper.xml 和 接口RoleMapper 以及POJO类RoleMapper之间的一些关系:
RoleMapper 接口中定义的getRole方法:
public Role getRole(Long id);
RoleMapper.xml配置文件中与该方法对应的SQL语句:
id 用来唯一标明这条 select 语句。它与RoleMapper.xml中 <mapper namespace>标签内容组合在一起,唯一标识了 这条 select 操作语句。这里的resultType="Role","Role"是在mybatisConfig.xml中定义的别名。
public Role getRole(Long id);
几种传 多个参数 给SQL语句的方法:
一,通过Map对象传参数
RoleMapper中定义的findRoleByMap方法
public ListfindRoleByMap(Map params);
当我们需要根据多个 参数 查找数据库时,且查找的结果也可能返回多条记录时,就使用上面的配置。
paramterType="map",传入一个map对象作为select语句的参数,其中map中的每个元素的key 对应 while子句中的#{roleName},#{note}
由于这里的while子句 只根据 两个参数 来查询,因此map的长度为2. 而map的value,则是 查询的条件的值。
MapparamsMap = new HashMap<>(); paramsMap.put("roleName", "me");//value是要满足的条件值 while note = "me" paramsMap.put("note", "no");//Key与sql语句中的 #{note} #{roleName}一致 List 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则是 相应的 结果值)
<id property="id" column="id" 表明 id 是 t_role表的主键,主键的列名是 "id"
<result property="roleName" colum="role_name"/> 表明:roleName是POJO类的属性名,"role_name"是数据库表t_role的列名,将二者对应起来。
二,使用参数注解的方式传递多个参数
或者使用更“易懂“的映射方法:----参数注解
RoleMapper接口里面定义的方法:
public ListfindRoleByAnnotation(@Param("roleName")String roleName, @Param("note")String note);
RoleMapper.xml配置文件里面的定义的SQL语句:这里就没有 paramterType 来定义查询的参数了
客户端 调用方法:这里,就可以不用HashMap封装多个待查询的参数了。
Listres = roleMapper.findRoleByAnnotation("me", "no");for (Role role2 : res) { System.out.println(role2); }
三,使用JAVA Bean对象传递参数:
RoleMapper.xml配置文件里面的定义的SQL语句:
RoleMapper.java接口方法:
public ListfindRoleByParam(RoleParam role);
客户端调用执行:
RoleParam rp = new RoleParam(); rp.setNote("note"); rp.setRoleName("test"); Listroles = roleMapper.findRoleByParam(rp);
批量插入操作:
RoleMapper.xml配置文件里面的定义的SQL语句:
insert into t_role(role_name, note) values (#{item.roleName},#{item.note})
useGeneratedKeys="true" 表明使用数据库表中自带的主键自增策略。在文章所述的t_role表的结构中, id 是自增的主键,但是这里的批量插入操作,并不需要显示的插入 id 的值。
待插入的每条记录值 放在 java.util.List 对象中保存,通过 foreach 循环遍历,"item"代表遍历到的每条记录---即每个Role对象, 通过 #{item.roleName} 和 #{item.note} 取出Role对象属性值---即每个表的字段值。
RoleMapper.java接口方法:public void insertBatch(ListroleList);
客户端调用执行:(记得最终 调用 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"); ListroleList = new ArrayList<>(); roleList.add(role2); roleList.add(role2); roleMapper.insertBatch(roleList); System.out.println("insert finished"); sqlSession.commit();
转载地址:http://zlujl.baihongyu.com/