1. 更新数据的基本方法
1.1 用于非查询SQL语句的SqlMap API
insert 方法:
Object insert(String id, Object parameterObject)
throws SQLException;
throws SQLException;
返回Object对象
update方法
int update(String id, Object parameterObject)
throws SQLException;
throws SQLException;
返回受影响记录数
delete 方法
int delete(String id, Object parameterObject)
throws SQLException;
throws SQLException;
返回删除记录数
1.2 非查询已映射语句
下表为表4-3 一部分
2.1 使用内联参数映射
</pre><pre name="code" class="html"><insert id="insertWithInlineInfo">
insert into account (
accountId,
username, password,
memberSince,
firstName, lastName,
address1, address2,
city, state, postalCode,
country, version
) values (
#accountId:NUMBER#,
#username:VARCHAR#, #password:VARCHAR#,
#memberSince:TIMESTAMP#,
#firstName:VARCHAR#, #lastName:VARCHAR#,
#address1:VARCHAR#, #address2:VARCHAR#,
#city:VARCHAR#, #state:VARCHAR#, #postalCode:VARCHAR#,
#country:VARCHAR#, #version:NUMBER#
)
</insert>
执行
Account account = new Account();
account.setAccountId(new Integer(9999));
account.setUsername("inlineins");
account.setPassword("poohbear");
account.setFirstName("Inline");
account.setLastName("Example");
sqlMapClient.insert("Account.insertWithInlineInfo", account);
2.2 使用外部参数映射
<parameterMap id="fullParameterMapExample" class="Account">
<parameter property="accountId" jdbcType="NUMBER" />
<parameter property="username" jdbcType="VARCHAR" />
<parameter property="password" jdbcType="VARCHAR" />
<parameter property="memberSince" jdbcType="TIMESTAMP" />
<parameter property="firstName" jdbcType="VARCHAR" />
<parameter property="lastName" jdbcType="VARCHAR" />
<parameter property="address1" jdbcType="VARCHAR" />
<parameter property="address2" jdbcType="VARCHAR" />
<parameter property="city" jdbcType="VARCHAR" />
<parameter property="state" jdbcType="VARCHAR" />
<parameter property="postalCode" jdbcType="VARCHAR" />
<parameter property="country" jdbcType="VARCHAR" />
<parameter property="version" jdbcType="NUMBER" />
</parameterMap>
<insert id="insertWithExternalInfo"
parameterMap="fullParameterMapExample">
insert into account (
accountId,
username, password,
memberSince
firstName, lastName,
address1, address2,
city, state, postalCode,
country, version
) values (
?,?,?,?,?,?,?,?,?,?,?,?,?
)
</insert>
2.3 自动生成的键
如果将数据库设计为使用自动生成的主键,就可以使用ibatis的<selectKey>元素(<insert>元素一个专用子元素)来获取这些自动生成的主键的值并将其保存在对象中
方式1:把记录插入到数据库中并且数据库为该记录自动生成主键之后,就立刻抓取该键值。
必须确保数据库驱动确实能返回你执行上一条insert语句所得到的键值。
方式2: 在插入记录之前就获取键值。
对此两种方式,ibatis都可以帮助轻松的完成任务。<selectKey>元素使得这个任务对应用程序完全透明。
insert 方法返回一个Object对象的原因:使你能够得到所生成的键值。
<insert id="insert">
<selectKey
keyProperty="accountId"
resultClass="int">
SELECT nextVal('account_accountid_seq')
</selectKey>
INSERT INTO Account (
accountId, username, password
) VALUES(
#accountId#, #username#, #password#)
</insert>
Integer returnValue = (Integer) sqlMap.insert(
"Account.insert", account);
<selectKey>元素其实也定义一个已映射语句,并且该已映射语句可以访问的参数映射与包含该已映射语句的insert语句相同。
<insert id="insertSequence">
<selectKey keyProperty="accountId" resultClass="int">
SELECT nextVal(#sequence#)
</selectKey>
INSERT INTO Account (
accountId, username, password
) VALUES(
#accountId#, #username#, #password#)
</insert>
如果使用Microsoft SQL Server
<insert id="insert">
INSERT INTO Account (
username, password
) VALUES(
#username#, #password#)
<selectKey
keyProperty="accountId"
resultClass="int">
SELECT SCOPE_IDENTITY()
</selectKey>
</insert>
3. 更新和删除数据
3.1 处理并发更新
ibatis没有实现的功能:为记录提供某种形式的锁。
可是使用若干技术来处理并发更新:时间戳或者为数据库表中的每条记录加一个版本号。
CREATE TABLE account (
accountid serial NOT NULL,
username varchar(10),
passwd varchar(10),
firstname varchar(30),
lastname varchar(30),
address1 varchar(30),
address2 varchar(30),
city varchar(30),
state varchar(5),
postalcode varchar(10),
country varchar(5),
version int8,
CONSTRAINT account_pkey PRIMARY KEY (accountid)
)
同时使用accountId字段和version字段。 根据返回值判断
3.2 更新或删除子记录
在应用程序的数据层处理对象关系
public void saveOrder(SqlMapClient sqlMapClient, Order order) throws SQLException {
if (null == order.getOrderId()) {
sqlMapClient.insert("Order.insert", order);
} else {
sqlMapClient.update("Order.update", order);
}
sqlMapClient.delete("Order.deleteDetails", order);
for (int i = 0; i < order.getOrderItems().size(); i++) {
OrderItem oi = (OrderItem) order.getOrderItems().get(i);
oi.setOrderId(order.getOrderId());
sqlMapClient.insert("OrderItem.insert", oi);
}
}
没有提供任何形式的事务隔离。
4. 运行批量更新
public void saveOrder(SqlMapClient sqlMapClient, Order order) throws SQLException {
sqlMapClient.startTransaction();<span style="white-space:pre"> </span>//打包为事务
try {
if (null == order.getOrderId()) {
sqlMapClient.insert("Order.insert", order);
} else {
sqlMapClient.update("Order.update", order);
}
sqlMapClient.startBatch();<span style="white-space:pre"> </span>///批处理
sqlMapClient.delete("Order.deleteDetails", order);
for (int i = 0; i < order.getOrderItems().size(); i++) {
OrderItem oi = (OrderItem) order.getOrderItems().get(i);
oi.setOrderId(order.getOrderId());
sqlMapClient.insert("OrderItem.insert", oi);
}
sqlMapClient.executeBatch();<span style="white-space:pre"> </span>///
sqlMapClient.commitTransaction();<span style="white-space:pre"> </span>//
} finally {
sqlMapClient.endTransaction();
}
}
如果使用selectKey语句来更新所插入对象的系统生成键,
那么他们将为所生成的键返回空值
5. 使用存储过程
5.1 优缺点分析
1.千万不要走极端
2.使用恰当的工具来工作
5.2 IN、OUT和INOUT参数
CREATE OR REPLACE FUNCTION max_in_example
(a float4, b float4)
RETURNS float4 AS
$BODY$
BEGIN
if (a > b) then
return a;
else
return b;
end if;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
以下是使用这个存储过程的参数映射、已映射语句及Java代码
<parameterMap id="pm_in_example" class="java.util.Map">
<parameter property="a" />
<parameter property="b" />
</parameterMap>
<procedure id="in_example" parameterMap="pm_in_example"
resultClass="int" >
{ call max_in_example(?, ?) }
</procedure>
// Call a max function
Map m = new HashMap(2);
m.put("a", new Integer(7));
m.put("b", new Integer(5));
Integer val =
(Integer)sqlMap.queryForObject("Account.in_example", m);
in out
create procedure swap(a in out integer, b in out integer) as
temp integer;
begin
temp := a;
a := b;
b := temp;
end;
以下是使用这个存储过程的参数映射、已映射语句及Java代码
<parameterMap id="swapProcedureMap" class="java.util.Map">
<parameter property="a" mode="INOUT" />
<parameter property="b" mode="INOUT" />
</parameterMap>
<procedure id="swapProcedure" parameterMap="swapProcedureMap">
{ call swap(?, ?) }
</procedure>
// Call swap function
Map m = new HashMap(2);
m.put("a", new Integer(7));
m.put("b", new Integer(5));
Integer val =
(Integer) sqlMap.queryForObject("Account.in_example", m);
out(Oracle PL/SQ L)
create or replace procedure maximum
(a in integer, b in integer, c out integer) as
begin
if (a > b) then c := a; end if;
if (b >= a) then c := b; end if;
end;
以下是使用这个存储过程的参数映射、已映射语句及Java代码
<parameterMap id="maxOutProcedureMap" class="java.util.Map">
<parameter property="a" mode="IN" />
<parameter property="b" mode="IN" />
<parameter property="c" mode="OUT" />
</parameterMap>
<procedure id="maxOutProcedure"
parameterMap="maxOutProcedureMap">
{ call maximum (?, ?, ?) }
</procedure>
// Call maximum function
Map m = new HashMap(2);
m.put("a", new Integer(7));
m.put("b", new Integer(5));
sqlMap.queryForObject("Account.maxOutProcedure", m);
// m.get("c") should be 7 now.