虽然iBatis更名为MyBatis,同时版本也更新到3.X,并且功能也更加完善和方便使用,但对于很多人来说2.X的稳定性和安全性更值得留恋,更多的是遗留的项目大多都使用的2.X版本!刚开始学习ORM框架时,使用的是Hibernate,深感其功能的强大,但同时感觉到其效率优化是个很大的问题(看到其发出的HQL和SQL语句就觉得蛋碎还有各种参数的调整优化),没有很多的经验积累无法做出很好的性能优化!出现的情况就是反而不如使用JDBC开发时性能来得高。后来同学实习时他公司使用了ibatis,看到SQLMAP时眼前一亮,心说这个就是我想要的,直接用SQL语言来做自己想做的事,在源头解决效率问题(优化SQL)总是令人愉快的,并且参数优化也相对简单。更主要的是自己练习的项目基本是中小型居多(太小的还是直接JDBC吧,用ibatis配置文件会把你搞烦的,虽然有ibator帮忙),此篇文章为学习总结整理,希望对那些想要入门的同学或同仁有所帮助!
首先,你所要准备的东西有:ibatis、log4j架包,安装有ORACLE数据库或MySQL数据库(因为目前我只使用这2个
)以及相应的jdbc驱动包(ORACLE的驱动在安装目录里的product\11.2.0\dbhome_1\jdbc\lib这个下面,MySQL的google一下有很多)。
接下来是代码部分,我全沾了,后面跟个打包,想要跑一下的(其实你直接下个去跑跑,改改也就入门了),MyEclipse直接导入,Eclipse建个同名项目,包复制进去,建立Java EE6 library和jdk1.6 library,导入驱动包和上面的包就行。
目录结构:
Model(POJO)以及sqlmap,sqlmapcofig和DAO:
Model:
package model;
public class Ibatis {
private int id;
private String account;
private String paswd;
private String gender;
private String phone;
public String toString(){
return "id:"+this.getId()+" account:"+this.getAccount()+" paswd:"+this.getPaswd()+" gender:"+this.getGender()+" phone:"+this.getPhone();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPaswd() {
return paswd;
}
public void setPaswd(String paswd) {
this.paswd = paswd;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
sqlmap(iBatis.xml):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="learn">
<!-- 重命名类名,将其作为一个类型,可在返回和参数类型设置时使用,在此命名空间内有效 -->
<typeAlias alias="iba" type="model.Ibatis" />
<!-- 定义返回MAP,此MAP用于ibatis接受数据库返回数据时自动封装到相应POJO类中 -->
<resultMap id="iBatis_Result" class="iba">
<result property="id" column="id" />
<result property="account" column="account" />
<result property="paswd" column="paswd" />
<result property="gender" column="gender" />
<result property="phone" column="phone" />
<!-- property属性与POJO类属性对应,column与数据库select语句中查询列名一致,
如果用了别名,这里也要用别名。在解决一对多,多对多问题时,这里可以用<result property="POJO中子POJO对应LIst属性名" resultMap="命名空间.resultMap的ID" />的形式
前提是你已经为List的POJO设置了一个resultMap-->
</resultMap>
<!-- 数据查询 -->
<select id="select_All" resultMap="iBatis_Result" parameterClass="string">
SELECT * FROM IBATISLEARN
</select>
<!-- 用MAP作为参数类型,ibatis的取实参较为安全的形式为:
#参数名#,使用like时为:“'%$参数名$%'” parameterClass默认为Map方式,即便你不定义,ibatis也自动将其作为Map方式处理,需传入对象需定义为对象-->
<select id="select_Login" parameterClass="java.util.Map"
resultMap="iBatis_Result">
select
id,
account,
paswd,
gender,
phone
from IBATISLEARN
where account = #account# and paswd = #paswd#<!-- 此处的参数名必须与map中的key值一样 -->
</select>
<select id="select_one" parameterClass="iba"
resultMap="iBatis_Result">
select
id,
account,
paswd,
gender,
phone
from IBATISLEARN
where account = #account# and paswd = #paswd#<!-- 此处的参数名必须与对象中的属性名一样 -->
</select>
<!-- 动态条件查询 -->
<select id="select_Dynamic" parameterClass="iba" resultMap="iBatis_Result">
select id,account,paswd,gender,phone
from IBATISLEARN
<!-- 当传入对象有某个属性不为空时(这里可以使用的判断条件还可以是其他的,不止isNotEmpty)。在上面SQL中加入where并追加条件 -->
<dynamic prepend="where">
<isNotEmpty prepend="and" property="account">
account like '%$account$%'
</isNotEmpty>
<isNotEmpty prepend="and" property="paswd">
paswd = #paswd#
</isNotEmpty>
<isNotEmpty prepend="and" property="gender">
gender = #gender#
</isNotEmpty>
<isNotEmpty prepend="and" property="phone">
phone like '%$phone$%'
</isNotEmpty>
</dynamic>
</select>
<!--
在配置文件中SQL语句可以分开来写:
<sql id="sub_Select">
select * from ibatislearn
</sql>
<sql id="sub_Where">
where account like #account#
</sql>
<select id="all_select" parameterClass="iba" resultMap="iBatis_Result">
<include refid="sub_Select"/>
<include refid="sub_Where"/>
</select>
另外还可以将SQL语句写在XML的DATA节点中
-->
<!-- 数据插入,数据插入时,ID如果是序列,可直接使用sequence.nextval插入ID,如果是数据库有自增,则不必插入ID -->
<insert id="insert_Ibatis" parameterClass="iba">
<selectKey resultClass="int" keyProperty="id" >
SELECT IBATIS_ID.NEXTVAL AS id FROM dual
</selectKey>
insert into IBATISLEARN (
id,
account,
paswd)
values (#id#,
#account#, #paswd#
)
</insert>
<!-- 动态插入 -->
<insert id="insert_Dynamic" parameterClass="iba" >
<selectKey resultClass="int" keyProperty="id" >
SELECT IBATIS_ID.NEXTVAL AS id FROM dual
</selectKey>
insert into IBATISLEARN
<dynamic prepend="(" >
id,
<isNotNull prepend="," property="account" >
account
</isNotNull>
<isNotNull prepend="," property="paswd" >
paswd
</isNotNull>
<isNotNull prepend="," property="gender" >
gender
</isNotNull>
<isNotNull prepend="," property="phone" >
phone
</isNotNull>
)
</dynamic>
values
<dynamic prepend="(" >
#id#,
<isNotNull prepend="," property="account" >
#account#
</isNotNull>
<isNotNull prepend="," property="paswd" >
#paswd#
</isNotNull>
<isNotNull prepend="," property="gender" >
#gender#
</isNotNull>
<isNotNull prepend="," property="phone" >
#phone#
</isNotNull>
)
</dynamic>
</insert>
<!-- 更新 -->
<update id="update_Ibatis" parameterClass="iba">
update IBATISLEARN set
paswd =
#paswd#
where
account = #account#
</update>
<!-- 动态更新 -->
<update id="update_Dynamic" parameterClass="iba" >
update IBATISLEARN
<dynamic prepend="set" >
<isNotNull prepend="," property="account" >
account = #account#
</isNotNull>
<isNotNull prepend="," property="paswd" >
paswd = #paswd#
</isNotNull>
<isNotNull prepend="," property="gender" >
gender = #gender#
</isNotNull>
<isNotNull prepend="," property="phone" >
phone = #phone#
</isNotNull>
</dynamic>
where id = #id#
</update>
<!-- 删除 -->
<delete id="delete_Ibatis" parameterClass="string">
delete from IBATISLEARN
where account = #account#
</delete>
</sqlMap>
SqlMapConfig.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings cacheModelsEnabled="true" enhancementEnabled="true"
lazyLoadingEnabled="true" maxRequests="200" maxSessions="100"
maxTransactions="20" useStatementNamespaces="true" />
<!-- 事务管理配置 -->
<transactionManager type="JDBC">
<dataSource type="SIMPLE">
<property value="oracle.jdbc.driver.OracleDriver" name="JDBC.Driver"/>
<property value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" name="JDBC.ConnectionURL"/>
<property value="scott" name="JDBC.Username"/>
<property value="tiger" name="JDBC.Password"/>
</dataSource>
</transactionManager>
<!-- 映射文件配置,用"com/yanglong/dao/study.xml"的形式 -->
<sqlMap resource="dao/iBatis.xml" />
</sqlMapConfig>
DAO(IbatisDAO.java):
package dao;
import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import model.Ibatis;
import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
/**
* learn DAO
*
* @author Dream.YangLong
*
*/
public class IbatisDAO {
private Reader reader;
private SqlMapClient sqlMap;
public IbatisDAO(){
try {
reader = Resources.getResourceAsReader("SqlMapConfig.xml");
} catch (IOException e) {
System.out.println("reader初始化错误!");
e.printStackTrace();
}
sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
}
/**
* 查询单个对象数据
*
* @param ib
* 封装有帐号和密码的对象
* @return 符合条件的单个对象
*/
public Ibatis queryOne(Ibatis ib) throws SQLException, IOException {
ib = (Ibatis) sqlMap.queryForObject("learn.select_one", ib);
return ib;
}
public Ibatis queryOne(Map<String, String> map) throws SQLException,
IOException {
Ibatis ib = (Ibatis) sqlMap.queryForObject("learn.select_Login", map);
return ib;
}
/**
* 查询多条数据,1个亦可,但需传入主键或者唯一列值
*
* @param ib
* 封装有查询条件的对象
* @return 含有信息的链表
*/
public List<Ibatis> queryMore(Ibatis ib) throws SQLException, IOException {
@SuppressWarnings("unchecked")
List<Ibatis> ibs = sqlMap.queryForList("learn.select_Dynamic", ib);
return ibs;
}
/**
* 查询所有的记录
*
* @return 所有记录
* @throws SQLException
* @throws IOException
*/
public List<Ibatis> queryMore() throws SQLException, IOException {
@SuppressWarnings("unchecked")
List<Ibatis> ibs = sqlMap.queryForList("learn.select_All", "1");
return ibs;
}
/**
* 新增帐号密码(持久操作)
*
* @param ib
* 需新增对象
* @throws SQLException
* 异常
*/
public void insertIbatis(Ibatis ib) throws SQLException {
sqlMap.insert("learn.insert_Ibatis", ib);
}
/**
* 新增(持久操作)
*
* @param ib
* 需新增对象
* @throws SQLException
* 异常
*/
public void insertIbatisDy(Ibatis ib) throws SQLException {
sqlMap.insert("learn.insert_Dynamic", ib);
}
/**
* 更新数据
*
* @param ib
* 更新对象,需要封装id入对象才能更新
* @throws SQLException
* 异常
*/
public void updateIbatis(Ibatis ib) throws SQLException {
sqlMap.update("learn.update_Dynamic", ib);
}
/**
* 删除数据
*
* @param account
* 需要删除的帐号
* @throws SQLException
* 异常
*/
public void deleteIbatis(String account) throws SQLException {
sqlMap.delete("learn.delete_Ibatis", account);
}
public Reader getReader() {
return reader;
}
public void setReader(Reader reader) {
this.reader = reader;
}
public SqlMapClient getSqlMap() {
return sqlMap;
}
public void setSqlMap(SqlMapClient sqlMap) {
this.sqlMap = sqlMap;
}
}
services(IbatisServices.java):
package services;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import dao.IbatisDAO;
import model.Ibatis;
/**
* ibatis学习services类,services类处理异常并产生日志
*
* @author Dream.YangLong
*
*/
public class IbatisServices {
private Ibatis iba;
private IbatisDAO ibo=new IbatisDAO();
private List<Ibatis> ibs;
/**
* 新增数据,只有帐号密码
*
* @param ib
* 需新增(持久化)对象
* @return true or false,成功或失败
*/
public boolean insertIbatis(Ibatis ib) {
try {
ibo.insertIbatis(ib);
} catch (SQLException e) {
System.out.println("新增失败!");
e.printStackTrace();
return false;
}
return true;
}
/**
* 动态新增数据,有什么增加什么
*
* @param ib
* 需新增对象
* @return true or false
*/
public boolean insertIbatisDy(Ibatis ib) {
try {
ibo.insertIbatisDy(ib);
} catch (SQLException e) {
System.out.println("新增失败!");
e.printStackTrace();
return false;
}
return true;
}
/**
* 单个查询,测试使用pojo时查询
*
* @param ib
* 封装有account和paswd字段的Ibatis对象
* @return 查询后所得结果封装成的对象
*/
public Ibatis queryOne(Ibatis ib) {
try {
ib = ibo.queryOne(ib);
} catch (SQLException e) {
System.out.println("queryOne(Ibatis ib)查询出现SQL异常!");
e.printStackTrace();
return null;
} catch (IOException e) {
System.out.println("queryOne(Ibatis ib)查询出现IO异常!");
e.printStackTrace();
return null;
}
return ib;
}
/**
* 单个查询,测试使用Map参数
*
* @param map
* 有account和paswd属性的map
* @return 查询后所得结果封装成的对象
*/
public Ibatis login(Map<String, String> map) {
try {
iba = ibo.queryOne(map);
} catch (SQLException e) {
System.out.println("login(Map<String,String> map)查询出现SQL异常!");
e.printStackTrace();
return null;
} catch (IOException e) {
System.out.println("login(Map<String,String> map)查询出现IO异常!");
e.printStackTrace();
return null;
}
return iba;
}
/**
* 动态条件查询多个对象数据
*
* @param ib
* 封装有条件的Ibatis对象
* @return 满足条件的ibatis对象链表
*/
public List<Ibatis> queryMore(Ibatis ib) {
try {
ibs = ibo.queryMore(ib);
} catch (SQLException e) {
System.out.println("queryMore(Ibatis ib)查询出现SQL异常!");
e.printStackTrace();
return null;
} catch (IOException e) {
System.out.println("queryMore(Ibatis ib)查询出现IO异常!");
e.printStackTrace();
return null;
}
return ibs;
}
/**
* 查询所有对象数据
*
* @return 所有对象数据链表
*/
public List<Ibatis> queryMore() {
try {
ibs = ibo.queryMore();
} catch (SQLException e) {
System.out.println("queryMore()查询出现SQL异常!");
e.printStackTrace();
return null;
} catch (IOException e) {
System.out.println("queryMore()查询出现IO异常!");
e.printStackTrace();
return null;
}
return ibs;
}
/**
* 数据更新,此方法依赖对象id
*
* @param ib
* 需要更新的对象,必须封装入ID
* @return true or false,成功或失败
*/
public boolean updateIbatis(Ibatis ib) {
try {
ibo.updateIbatis(ib);
} catch (SQLException e) {
System.out.println("更新失败!");
e.printStackTrace();
return false;
}
return true;
}
/**
* 删除数据,此方法依赖帐号
*
* @param account
* 帐号
* @return true or false,成功或失败
*/
public boolean deleteIbatis(String account) {
try {
ibo.deleteIbatis(account);
} catch (SQLException e) {
System.out.println("删除失败!");
e.printStackTrace();
return false;
}
return true;
}
}
测试类TestClass.java:
package test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import services.IbatisServices;
import model.Ibatis;
/**
* ibatis学习Services测试类
*
* @author Dream.YangLong
*
*/
public class TestClass {
private Ibatis ib;
private IbatisServices ibss = new IbatisServices();
private List<Ibatis> ibs;
private static Logger logger = Logger.getLogger(TestClass.class);
// 新增,只有帐号密码
public void addIba() {
ib = new Ibatis();
ib.setAccount("testaccount1");
ib.setPaswd("testpaswd1");
boolean flag = ibss.insertIbatis(ib);
if (flag)
System.out.println("新增成功!");
else
System.out.println("新增失败!");
}
/**
* 新增,动态信息
*/
public void addIbaDy() {
ib = new Ibatis();
ib.setAccount("testaccount2");
ib.setPaswd("testpaswd2");
ib.setGender("女");
boolean flag = ibss.insertIbatisDy(ib);
if (flag)
System.out.println("新增成功!");
else
System.out.println("新增失败!");
}
/**
* 单个查询,测试POJO
*/
public void queryOne() {
ib = new Ibatis();
ib.setAccount("testaccount1");
ib.setPaswd("testpaswd1");
ib = ibss.queryOne(ib);
if (ib != null)
System.out.println("单个查询,测试pojo:" + ib.toString());
else
System.out.println("查询为空!");
}
/**
* map查询
*/
public void login() {
Map<String, String> map = new HashMap<String, String>();
map.put("account", "testaccount1");
map.put("paswd", "testpaswd1");
ib = ibss.login(map);
if (ib != null)
System.out.println("单个查询,测试map:" + ib.toString());
else
System.out.println("查询为空!");
}
/**
* 多个查询,模糊匹配
*/
public void queryMore() {
ib = new Ibatis();
System.out.println(ib.getId());
ib.setPhone("1");
ib.setAccount("test");
ibs = ibss.queryMore(ib);
for (Ibatis ibe : ibs) {
System.out.println(ibe.toString());
System.out.println("=========================");
}
}
/**
* 多个查询,查询所有
*/
public void queryAll() {
ibs = ibss.queryMore();
for (Ibatis ibe : ibs) {
System.out.println(ibe.toString());
System.out.println("=========================");
}
}
/**
* 根据ID动态更新
*/
public void updateInfo() {
ib = new Ibatis();
ib.setId(1);
ib.setAccount("updatetest1");
boolean flag = ibss.updateIbatis(ib);
if (flag)
System.out.println("更新成功!");
else
System.out.println("更新失败!");
}
/**
* 根据帐号删除信息
*/
public void deleteInfo() {
boolean flag = ibss.deleteIbatis("testaccount2");
if (flag)
System.out.println("删除成功!");
else
System.out.println("删除失败!");
}
public Ibatis getIb() {
return ib;
}
public void setIb(Ibatis ib) {
this.ib = ib;
}
public IbatisServices getIbss() {
return ibss;
}
public void setIbss(IbatisServices ibss) {
this.ibss = ibss;
}
public static void main(String[] args) {
TestClass test = new TestClass();
logger.info("测试");
// 新增
test.addIba();
test.addIbaDy();
// 查询
test.queryOne();
test.login();
test.queryMore();
test.queryAll();
// 更新
test.updateInfo();
// 删除
test.deleteInfo();
}
}
log4j配置文件log4j.properties:
#log4j.rootLogger = [ level ] , appenderName, appenderName, ...
log4j.rootLogger = INFO, console, R
#level=INFO,all can be output
#console is set to be a ConsoleAppender
log4j.appender.console = org.apache.log4j.ConsoleAppender
#console have four patterns
#org.apache.log4j.HTMLLayout
#org.apache.log4j.PatternLayout
#org.apache.log4j.SimpleLayout
#org.apache.log4j.TTCCLayout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
#define the output type
log4j.appender.console.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
log4j.logger.com.ibatis=debug
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=debug
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=debug
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=debug
log4j.logger.java.sql.Connection=debug
log4j.logger.java.sql.Statement=debug
log4j.logger.java.sql.PreparedStatement=debug
#file is set to output to a extra file
log4j.appender.R = org.apache.log4j.RollingFileAppender
#the absolute route of the log4j file
log4j.appender.R.File = /log.txt
#the size
log4j.appender.R.MaxFileSize = 500KB
#back up a file
log4j.appender.R.MaxBackupIndex = 1
log4j.appender.R.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} %5p [%F\:%L] %c{8}.%M() - %m%n
OK!基本就是这样子,ORACLE使用触发器实现主键自增的方法:insert语句中省去ID字段相关的东西,在数据库中创建类似这样的触发器:
create or replace trigger tr_ibid
before insert on ibatislearn
for each row
declare
begin
select ibatis_id.nextval into :new.id from dual;
end tr_ibid;
另外iBatis的n+1问题(一次目的查询在数据库查询了2次,其实就是外键问题,要取到被关联主键的所有信息),此处有详解http://cuishen.iteye.com/blog/544207
ibatis比较容易学习,但写代码的时候要细心,可能少个符号就报一堆错,千万记住!