爱游戏全站app官网入口-爱游戏官网

由“单独搭建mybatis”到“mybatis与spring的整合/集成” -爱游戏全站app官网入口

2023-08-21,,

在j2ee领域,hibernate与mybatis是大家常用的持久层框架,它们各有特点,在持久层框架中处于领导地位。

本文主要介绍mybatis(对于较小型的系统,特别是报表较多的系统,个人偏向mybatis),对于它,个人比较喜欢的是:

使用简单、方便;
支持的xml动态sql的编写,方便浏览、修改,同时降低sql与应用程序之间的耦合。

不喜欢的是:

出现错误时,调试不太方便

本文主要介绍mybatis的搭建,是学习mybatis过程后整理的札记,其中包括“搭建mybaits”和常用的“mybatis与spring的整合”。

一、数据库的准备

因为mybatis是持久层框架,毫无疑问,是需要操作数据库的。所以,在搭建之前,我们需要先创建一个简单的表。

create table t_user_test_1407
(
username varchar2(255),
password varchar2(255)
)

sql - ddl - create table

插入一些数据,以作查询的测试。

insert into t_user_test_1407 (username, password)
values ('nick', 'optimistic,confident,love - 1');

sql - dml - insert table

二、单独搭建mybaits

1)环境准备、版本说明

此工程使用jdk1.6  mybatis-3.2.4 oracle11g。

新建一个web工程,由于只构建mybatis,只引用mybatis和oracle jdbc驱动包

mybatis-3.2.4.jar
ojdbc6.jar

2)程序的搭建

首先,我们将数据源等配置信息放在一个xml,让mybatis可以根据这个信息去连接数据库、管理事务。

目前我们可只关注environments节点,此节点是用于配置数据源、事务管理的 。

其他的节点,如typealiases、mappers,是用于注册一些信息的,后面会陆续提到。

 
public "-//mybatis.org//dtd config 3.0//en"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

















mybatis-config.xml

既然有了配置的xml,下一步就需要让mybatis加载它了。

    首先以输入流的形式加载xml
    以“sqlsessionfactorybuilder -> sqlsessionfactory -> sqlsession”的流程最后构建出sqlsession。
    sqlsession,顾名思义,是一次会话,是应用程序与数据库交互的会话,所以,其生命周期应在一次数据库连接之间,当然,此次数据库连接可以包含一次或多次数据库操作。
    sqlsessionfactory,顾名思义,是sqlsession的工厂类,用于产出sqlsession。我们知道,sqlsession主要用于数据库操作,而数据库操作又是贯穿于应用程序整个生命周期当中的,那么,"产出sqlsession"这个动作也应当贯穿于应用程序整个生命周期当中,所以,sqlsessionfactory的生命周期一般为应用程序的整个生命周期,一般为单例/static的形式存在。
    sqlsessionfactorybuilder,由代码可见,其主要作用是从配置文件中获取配置信息,然后构建sqlsessionfactory,所以其生命周期可以是临时的,局部的。
    通过sqlsession获取usermapper接口,再调用该接口的数据操纵方法。
package com.nicchagil.mybatisonly;
import java.io.ioexception;
import java.io.inputstream; 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.nicchagil.mybatisonly.bean.user;
import com.nicchagil.mybatisonly.mapper.usermapper; public class call { public static sqlsessionfactory sqlsessionfactory = null; public static void main(string[] args) throws ioexception { // query user
/*
kickstartmybatis();
queryuser("nick");
*/ // inser user
kickstartmybatis();
insertuser("user004", "hello world."); } public static void kickstartmybatis() throws ioexception {
string resource = "com/nicchagil/mybatisonly/mybatis-config.xml";
inputstream inputstream = resources.getresourceasstream(resource);
sqlsessionfactory = new sqlsessionfactorybuilder().build(inputstream);
} /**
* query user
* @param username
* @return
*/
public static user queryuser(string username) { user user = null;
sqlsession session = sqlsessionfactory.opensession();
try { /* un-recommended method */
/*
user = (user)session.selectone("com.nicchagil.mybatisonly.mapper.usermapper.queryuser", username);
*/ /* recommended method */
usermapper usermapper = session.getmapper(usermapper.class);
user = usermapper.queryuser(username); system.out.println("username - " user.getusername() " , password - " user.getpassword()); } finally {
session.close();
} return user;
} /**
* insert user
* @param username
* @param password
*/
public static void insertuser(string username, string password) { sqlsession session = sqlsessionfactory.opensession(); try { usermapper usermapper = session.getmapper(usermapper.class); user user = new user();
user.setusername(username);
user.setpassword(password); usermapper.insertuser(user); // flushes batch statements and commits database connection.
// note that database connection will not be committed if no updates/deletes/inserts were called.
session.commit(); system.out.println("username - " user.getusername() " , password - " user.getpassword()); } catch (exception e) {
session.rollback();
e.printstacktrace(); //todo print the exception logs
//todo prompts fail to execute for user } finally {
session.close();
} } /**
* insert user
* @param username
* @param password
*/
public static void insertuserbysql(string username, string password) { sqlsession session = sqlsessionfactory.opensession(); try { user user = new user();
user.setusername(username);
user.setpassword(password); session.insert("com.nicchagil.mybatisonly.mapper.usermapper.insertuser", user); // flushes batch statements and commits database connection.
// note that database connection will not be committed if no updates/deletes/inserts were called.
session.commit(); } catch (exception e) {
session.rollback();
e.printstacktrace(); //todo print the exception logs
//todo prompts fail to execute for user } finally {
session.close();
} } }

call

usermapper是一个dao的接口,是定义作哪些数据库操作的。

 package com.nicchagil.mybatisonly.mapper;
 import com.nicchagil.mybatisonly.bean.user;
 public interface usermapper {
     public user queryuser(string username);
 }

usermapper.java

usermapper只是供调用的接口,那么具体的实现逻辑在哪里呢?

我们可见usermaper.xml,它定义的sql就是用于定义usermapper接口的实现。我们需在mybatis-config.xml注册usermaper.xml,可见mybatis-config.xml的mappers节点。

我们可以看到id为queryuser,与接口的方法名对应;
sql我们很熟悉了,就是一个简单的sql,而#{username},就是接口方法的入参;
resulttype为"user",这个user是一个别名,具体对应com.nicchagil.mybatisonly.bean.user这个类,我们可以看到在mybatis-config.xml文件的typealiases节点中已经注册它们的映射关系。


public "-//mybatis.org//dtd mapper 3.0//en"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

insert into t_user_test_1407 t (t.username, t.password) values (#{username}, #{password})

usermapper.xml

而com.nicchagil.mybatisonly.bean.user是实体类,用于装载数据。

 package com.nicchagil.mybatisonly.bean;
 public class user {
     private string username;
private string password; public string getusername() {
return username;
} public void setusername(string username) {
this.username = username;
} public string getpassword() {
return password;
} public void setpassword(string password) {
this.password = password;
} @override
public int hashcode() {
final int prime = 31;
int result = 1;
result = prime * result
((password == null) ? 0 : password.hashcode());
result = prime * result
((username == null) ? 0 : username.hashcode());
return result;
} @override
public boolean equals(object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getclass() != obj.getclass())
return false;
user other = (user) obj;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
} }

user.java

最后,我们运行call.java,将能成功查询、插入数据库。我们可通过打印的信息和查询数据库,以查看是否成功查询、插入数据。

3)事务说明

对于数据库有写操作的应用程序,一般来说,事务是不可或缺的一部分。因为未使用其他框架,这里使用编程式事务,即使用sqlsession.commit()和sqlsession.rollback()方法,可见call.java。

由于本程序对事务有异常回滚的要求,所以,需要获取非自动提交的sqlsession
如程序执行正常,则最后执行session.commit()以提交事务。
session.commit()有个需注意的地方,参考其如下注释,即如果当前会话中不涉及updates/deletes/insert等写数动作则不提交事务。所以,如果要触发mybatis提交事务,就需执行明确的触发动作,如“执行session.insert(...)方法”或“执行对应的sql mapper配置中的insert、update、delete等标签”等操作。(本人曾尝试在sql mapper配置中用select标签包含insert的sql,使用sqlsession.commit()后,执行正常,但没有提交事务,可见并未触发,所以,需规范使用标签)。如需强制提交,可用sqlsession.commit(boolean)。

flushes batch statements and commits database connection. note that database connection will not be committed if no updates/deletes/inserts were called. to force the commit call sqlsession.commit(boolean)

如程序执行异常,则回滚事务,session.rollback()

单独搭建mybaits完毕!

二、 mybatis与spring的整合

一个项目中,单独使用mybatis的情况并不多;更多的情况下,我们需要将mybatis与其他框架进行整合,以便更好地使用。比如mybatis spring,就是一个流行的整合组合。

1)环境准备、版本说明

本次用mybatis3 spring3进行整合。注意,并不包含mvc框架的配置,因为本文的目的是学习mybatis,所以尽量不引用其他框架,以避免影响代码的理解。

需引入的类库详情如下:


    
junit
junit
3.8.1
test

org.springframework
spring-context
3.2.10.release

org.springframework.webflow
spring-webflow
2.4.0.release

org.springframework.data
spring-data-oracle
1.0.0.release

org.mybatis
mybatis
3.2.4

org.mybatis
mybatis-spring
1.2.2

mvn dependencies

2)程序的搭建

首先,我们在spring中配置关于mybatis数据源的信息。

这里以applicationcontext-mybatis.xml来体现,配置了如下信息:

注册数据源,常见的有jdbc或jndi,根据具体情况择一。
注册sqlsessionfactory
sqlsessionfactory是用来生产sqlsession以操作数据库的,所以,需指定sqlsessionfactory所引用的数据源
指定相应的sql mapper文件在哪里。我们自命名“_mapper后缀的xml文件”,主要用来定义sql;“_resultmap后缀的xml文件”,则主要用来定义db字段与应用程序实体属性的映射。
指定相应的应用程序实体在哪里,并自动注册不包含package名的别名
在哪些package下扫描mapper接口,即dao接口


xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">



jndi_test_db





classpath:com/nicchagil/mybatis3spring3intg/mapper/sqlxml/*_mapper.xml
classpath:com/nicchagil/mybatis3spring3intg/bean/resultmapxml/*_resultmap.xml






applicationcontext-mybatis.xml

除了mybatis的信息,还有一些spring的信息需要配置:

根据注解自动扫描并注册bean
spring的声明式事务管理(用以替代上一章节的“编程式事务”)
由于本程序没有集成mvc框架,在servlet是通过spring编程式地获得spring管理的bean,所以这里注册一个spring的工具类。(使用了mvc框架并将框架交由spring ioc容器管理的,可忽视此点配置)


xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">



applicationcontext.xml

众所周知,以上是spring的配置文件,那么我们需要告诉应用程序“这些配置文件在哪里”,所以我们需要在web.xml中告诉应用程序。另外,此web.xml注册了一个servlet,用于接收页面的请求。



mybatis3spring3intg

index.html


org.springframework.web.context.contextloaderlistener


contextconfiglocation
classpath*:config/applicationcontext*.xml



userservlet
userservlet
com.nicchagil.mybatis3spring3intg.servlet.userservlet


userservlet
/userservlet

web.xml

我们还需要定义mapper的接口,即dao接口。此处的mapper的接口,我们已经在applicationcontext-mybatis.xml中注册为指定路径下自动扫描。

package com.nicchagil.mybatis3spring3intg.mapper;
import com.nicchagil.mybatis3spring3intg.bean.user;
public interface usermapper {
    public user find(string username);
    public void save(user user);
}

usermapper.java

而mapper的实现是如何的呢?

mybatis会帮我们实现,我们只需要通过user_mapper.xml文件告诉mybatis对应的sql,此处的mapper文件,已经在applicationcontext-mybatis.xml中注册为指定路径下自动扫描。


public "-//mybatis.org//dtd mapper 3.0//en"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

insert into t_user_test_1407 t (t.username, t.password) values (#{username}, #{password})

user_mapper.xml

可以看到,mapper和sql配置文件中都引用到了实体类,我们也需要定义。此处的实体类,已经在applicationcontext-mybatis.xml中注册为指定路径下自动扫描。

package com.nicchagil.mybatis3spring3intg.bean;
public class user {
    private string username;
private string password;
private string childhoodname; public string getusername() {
return username;
} public void setusername(string username) {
this.username = username;
} public string getpassword() {
return password;
} public void setpassword(string password) {
this.password = password;
} public string getchildhoodname() {
return childhoodname;
} public void setchildhoodname(string childhoodname) {
this.childhoodname = childhoodname;
} @override
public int hashcode() {
final int prime = 31;
int result = 1;
result = prime * result
((childhoodname == null) ? 0 : childhoodname.hashcode());
result = prime * result
((password == null) ? 0 : password.hashcode());
result = prime * result
((username == null) ? 0 : username.hashcode());
return result;
} @override
public boolean equals(object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getclass() != obj.getclass())
return false;
user other = (user) obj;
if (childhoodname == null) {
if (other.childhoodname != null)
return false;
} else if (!childhoodname.equals(other.childhoodname))
return false;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
} }

user.java

实体的属性与db的字段之间的映射/匹配,我们需要定义一下。此处的resultmap.xml文件已经在applicationcontext-mybatis.xml中注册为指定路径下自动扫描。








user_resultmap.xml

完成了dao,那么接着写service。

首先一个service的接口。

package com.nicchagil.mybatis3spring3intg.service;
import com.nicchagil.mybatis3spring3intg.bean.user;
public interface userservice {
    public user query(string username);
    public void save(user user);
    public void testtransaction(user user1, user user2);
}

userservice.java

service的实现类如下,这里只简单地测试查询、保存、事务是否能正常处理。

package com.nicchagil.mybatis3spring3intg.service.impl;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.service;
import org.springframework.transaction.annotation.transactional; import com.nicchagil.mybatis3spring3intg.bean.user;
import com.nicchagil.mybatis3spring3intg.mapper.usermapper;
import com.nicchagil.mybatis3spring3intg.service.userservice; @service
public class userserviceimpl implements userservice { @autowired
private usermapper mapper; @override
public user query(string username) {
return mapper.find(username);
} @override
public void save(user user) {
mapper.save(user);
} @override
@transactional
public void testtransaction(user user1, user user2) {
mapper.save(user1); // code a nullpointerexception to test transaction setting
string str = null;
str.charat(0); mapper.save(user2);
} }

userserviceimpl.java

由于没有整合mvc框架,此处由一个servlet(此servlet已于web.xml中注册)获取页面请求并调用service,

那么如何在servlet中获得spring ioc管理下service的bean呢?这里借助springcontextutil(implements applicationcontextaware),此springcontextutil于以上提及的applicationcontext.xml中注册。

package com.nicchagil.mybatis3spring3intg.servlet;
import java.io.ioexception;
import javax.servlet.servletexception;
import javax.servlet.http.httpservlet;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse; import com.nicchagil.mybatis3spring3intg.bean.user;
import com.nicchagil.mybatis3spring3intg.service.userservice;
import com.nicchagil.util.springcontextutil; /**
* servlet implementation class userservlet
*/
public class userservlet extends httpservlet {
private static final long serialversionuid = 1l; /**
* @see httpservlet#httpservlet()
*/
public userservlet() {
super();
// todo auto-generated constructor stub
} /**
* @see httpservlet#doget(httpservletrequest request, httpservletresponse response)
*/
protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
this.dopost(request, response);
} /**
* @see httpservlet#dopost(httpservletrequest request, httpservletresponse response)
*/
protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { string action = request.getparameter("action"); userservice service = (userservice)springcontextutil.getbean("userserviceimpl"); if ("find".equals(action)) {
user user = service.query(request.getparameter("username"));
system.out.println(user.getusername() " - " user.getpassword() " - " user.getchildhoodname()); } if ("save".equals(action)) {
user user = new user();
user.setusername(request.getparameter("username"));
user.setpassword(request.getparameter("password")); service.save(user);
system.out.println(user.getusername() " - " user.getpassword()); } if ("testtransaction".equals(action)) {
user user1 = new user();
user1.setusername(request.getparameter("username"));
user1.setpassword(request.getparameter("password")); user user2 = new user();
user2.setusername(request.getparameter("username") " - double");
user2.setpassword(request.getparameter("password") " - double"); service.testtransaction(user1, user2);
system.out.println(user1.getusername() " - " user1.getpassword());
system.out.println(user2.getusername() " - " user2.getpassword()); } } }

userservlet.java

package com.nicchagil.util;
import org.springframework.beans.beansexception;
import org.springframework.context.applicationcontext;
import org.springframework.context.applicationcontextaware; public class springcontextutil implements applicationcontextaware { private static applicationcontext applicationcontext = null; @override
public void setapplicationcontext(applicationcontext ac)
throws beansexception {
applicationcontext = ac; } public static applicationcontext getapplicationcontext() {
return applicationcontext;
} public static object getbean(string beanname) {
return applicationcontext.getbean(beanname);
} public static boolean containsbean(string beanname) {
return applicationcontext.containsbean(beanname);
} }

springcontextutil.java

几乎大功告成。

这里写了些触发测试的页面,执行结果可通过“查看控制台”或“查询数据库”获得。哈哈!~~

导航页





insert title here








index.html

输入username查询记录的触发页面





insert title here






find.html

保存页面





insert title here








save.html

测试事务的触发页面





insert title here








testtransaction.html

大功告成!!

分享于:

https://github.com/nicchagil/mybatis3spring3intg/tree/mybatis3spring3intg_branch_initialization

由“单独搭建mybatis”到“mybatis与spring的整合/集成”的相关教程结束。

网站地图