<![CDATA[ 到新单位一个星期了。研究以前没用过的ibats也有一个星期了,期间为了一个问题的实现用了N次GOOLE,最终还是自己解决了。发此帖的目的:
1、为了共享解决方案(在SQL2000下如何取得自增长ID,就本人亲测网上好多方法要么有隐患,要么无法实现。)
2、讨论若干疑问。
废话少说,直接上代码了。
[code="java"]
package com.ibatis.sample.bean;
import java.io.Serializable;
import org.springframework.stereotype.Repository;
/**
* @author summerPine(沙漠派)
* <Pre>
* email:xnxqs@163.com
* QQ:254120499
* MSN:xnxqs@hotmail.com
* 2009-7-20 下午02:12:05
* ibatisTest
* 转载请保留! ^_^
*</pre>
*creat sql:
*if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[t_user]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[t_user]
GO
CREATE TABLE [dbo].[t_user] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[name] [varchar] (10) COLLATE Chinese_PRC_CI_AS NULL ,
[sex] [int] NULL
) ON [PRIMARY]
GO
*/
@Repository
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Integer sex;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
// public Set<Address> getAddresses() {
// return addresses;
// }
//
// public void setAddresses(Set<Address> addresses) {
// this.addresses = addresses;
// }
// private Set<Address> addresses = new HashSet<Address>();
}
[/code]
简单的javabean,这个就不解说了吧。接下来是xml
[code="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="User">
<typeAlias alias="user" type="com.ibatis.sample.bean.User" />
<select id="getUser" parameterClass="user" resultClass="user">
select * from t_user where 1=1
<isNotEmpty prepend="AND" property="name">
name=#name#
</isNotEmpty>
<isNotEmpty prepend="AND" property="sex">
sex=#sex#
</isNotEmpty>
<isNotEmpty prepend="AND" property="id">
id=#id#
</isNotEmpty>
</select>
<update id="updateUser" parameterClass="user">
UPDATE t_user
SET
name=#name#,
sex=#sex#
WHERE id = #id#
</update>
<update id="updateUserByName" parameterClass="java.lang.String">
UPDATE t_user
SET
sex=#sex#
WHERE name = #name#
</update>
<!--[color=red]注一[/color]:就是这样地方花了我整整二天时间,网上的答案主要用二种,一种ibatis指南上推荐使用的:@@IDENTITY还有一种就如下面所示: SCOPE_IDENTITY(),按sql的帮助文档上所说:
SCOPE_IDENTITY 和 @@IDENTITY 返回在当前会话中的任何表内所生成的最后一个标识值。但是,SCOPE_IDENTITY 只返回插入到当前作用域中的值;@@IDENTITY 不受限于特定的作用域。
所以对于@@IDENTITY这个函数的使用,实质上是有一定隐患的,而一些网友筒志也有这种认识所以就有了下面的配置②,但经测试(测试环境:sql2000+sql2005的驱动包+myeclipse7.5)这样是无法取得返回ID的。因为ibatis把它当二条语句执行了,不在同一域所以没法取得ID值。(但本人所搜索出来的资料大都如此配置,所以对这个测试结果本人很不自信,不知道有没有朋友遇到过同样的问题。)无赖之下,捣鼓了半年,搞出了下面这种配置。经测试是绝对有效的。
-->
<insert id="addUser" parameterClass="user">
select 1;
<selectKey resultClass="int" keyProperty="id" type="post">
INSERT
INTO t_user (name,sex)VALUES (#name#,#sex#)
SELECT SCOPE_IDENTITY() AS
ID
</selectKey>
</insert>
<!--配置2insert id="addUser" parameterClass="user">
INSERT INTO t_user (name,sex)VALUES (#name#,#sex#)
<selectKey resultClass="int" keyProperty="id" type="post">
SELECT SCOPE_IDENTITY() AS ID
</selectKey>
</insert-->
<delete id="deleteUser" parameterClass="user">
delete from t_user
<dynamic prepend="WHERE">
<isNotEmpty prepend="AND" property="id">
id = #id#
</isNotEmpty>
<isNotEmpty prepend="AND" property="name">
name = #name#
</isNotEmpty>
<isNotEmpty prepend="AND" property="sex">
sex = #sex#
</isNotEmpty>
</dynamic>
</delete>
</sqlMap>
[/code]
接下来是Dao层。
[code="java"]
package com.ibatis.sample.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import com.ibatis.sqlmap.client.SqlMapClient;
public class BaseDao extends SqlMapClientDaoSupport {
@Autowired//为了注入SqlMapClient所以多了一个baseDao
public void setSqlMapClientBase(SqlMapClient sqlMapClient) {
super.setSqlMapClient(sqlMapClient);
}
}
[/code]
接口
[code="java"]
package com.ibatis.sample.dao;
import java.util.List;
import com.ibatis.sample.bean.User;
public interface IUserDao {
public User addUser(User user);
public int delUser(User user);
public void delUserById(User user);
public void delUserByName(User user);
public int updateUser(User user);
public User getUser(User user);
public List<User> getUsers(User user);
}
[/code]
实现:
[code="java"]
package com.ibatis.sample.dao.impl;
import java.sql.SQLException;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ibatis.sample.bean.User;
import com.ibatis.sample.dao.BaseDao;
import com.ibatis.sample.dao.IUserDao;
@Service
@Transactional
public class UserDao extends BaseDao implements IUserDao {
/*
* (non-Javadoc)
*
* @see
* com.ibatis.sample.dao.impl.IUserDao#insertUser(com.ibatis.sample.bean
* .User)
*/
public User addUser(User user) {
Integer id = (Integer) getSqlMapClientTemplate()
.insert("addUser", user);
// this.getSqlMapClient()
if (id != null)
user.setId(id);
else
user = null;
return user;
}
/*
* (non-Javadoc)
*
* @see
* com.ibatis.sample.dao.impl.IUserDao#delUser(com.ibatis.sample.bean.User)
*/
public int delUser(User user) {
return getSqlMapClientTemplate().delete("deleteUser", user);
}
/*
* (non-Javadoc)
*
* @see
* com.ibatis.sample.dao.impl.IUserDao#delUserById(com.ibatis.sample.bean
* .User)
*/
public void delUserById(User user) {
getSqlMapClientTemplate().delete("updateUserById", user);
}
/*
* (non-Javadoc)
*
* @see
* com.ibatis.sample.dao.impl.IUserDao#delUserByName(com.ibatis.sample.bean
* .User)
*/
public void delUserByName(User user) {
getSqlMapClientTemplate().delete("updateUserByName", user);
}
/*
* (non-Javadoc)
*
* @see
* com.ibatis.sample.dao.impl.IUserDao#updateUser(com.ibatis.sample.bean
* .User)
*/
public int updateUser(User user) {
return getSqlMapClientTemplate().update("updateUser", user);
}
public void updateUserByName(User user) {
getSqlMapClientTemplate().update("updateUserByName", user);
}
/*
* (non-Javadoc)
*
* @see
* com.ibatis.sample.dao.impl.IUserDao#getUser(com.ibatis.sample.bean.User)
*/
@Transactional(readOnly = true)
public User getUser(User user) {
return (User) getSqlMapClientTemplate().queryForObject("getUser", user);
}
/*
* (non-Javadoc)
*
* @see
* com.ibatis.sample.dao.impl.IUserDao#getUsers(com.ibatis.sample.bean.User)
*/
@SuppressWarnings("unchecked")
@Transactional(readOnly = true)
public List<User> getUsers(User user) {
return (List) getSqlMapClientTemplate().queryForList("getUser", user);
}
}
[/code]
测试类:
[code="java"]
package com.ibatis.sample.test;
import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.NotTransactional;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import com.ibatis.sample.bean.User;
import com.ibatis.sample.dao.IUserDao;
/**
* @author summerPine(沙漠派)
*
* <Pre>
* email:xnxqs@163.com
* QQ:254120499
* MSN:xnxqs@hotmail.com
* 2009-7-15 下午03:32:39
* ibatisTest
* 转载请保留! ˆ_ˆ
*</pre>
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserDaoTest {
@Autowired
IUserDao userDao;
@Autowired
User user;
static List<User> userList = new ArrayList<User>();
@Before
public void setUp() throws Exception {
System.out.println("setup被调用 ");
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
for (User u : userList) {
System.out.println(u.getId() + "--" + u.getName() + "--"
+ u.getSex());
}
}
@After
public void tearDown被调用() throws Exception {
if (user != null)
System.out.println("单个对象为:" + user.getId() + "--" + user.getName()
+ "--" + user.getSex());
System.out.println("tearDown被调用 ");
}
@Test
public void testGetUser() {
user.setId(60);
user = userDao.getUser(user);
// Assert.assertEquals(1, user.getId().intValue());
}
// @Test
// @Rollback(false)
// @NotTransactional
public void insertUser() {
user.setName("a2");
user.setSex(2);
user = userDao.addUser(user);
}
// @Test
public void testDelUser() {
user = new User();
user.setId(17);// 请填入一个存在的ID,否则不通过
System.out.println("**************************");
int rows = userDao.delUser(user);
Assert.assertFalse(rows == 0);
}
// @Test
public void testUpdateUser() {
user.setId(4);
user = userDao.getUser(user);
System.out.println("改前为:" + user.getId() + "--" + user.getName() + "--"
+ user.getSex());
user.setName("改动ING");
user.setSex(5);
int rows = userDao.updateUser(user);
Assert.assertFalse(rows == 0);
System.out.println("改后为:" + user.getId() + "--" + user.getName() + "--"
+ user.getSex());
}
//
//
// @Test
public void testGetUsers() {
user = new User();
user.setName("a2");
userList = userDao.getUsers(user);
}
}
[/code]
写到这里的时候,以上测试全部通过,但实际上这个例子太简单了,1.没有service,直接上的dao层,分层概念没有体现出来。2、没有测试事务。如是本人又有了以下的扩展测试:
扩展一:通用DAO。
扩展二:加了service层
扩展三:1:N的数据关联查询
扩展四:尝试1:n,N:M的N+1问题,没成功(最开始是因为对ibatis了解得太少,到后期了解稍深入一点以后,就发现自己的想法太天真了,但个人觉得还是有那么一点点一点的可取之处,所以在这里只会帖出扩展四的部分代码,以抛砖引玉。PS:我已运气于顶,请大家拍吧。。)。
javaBean
[code="java"]
package com.ibatis.sample.bean;
import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.stereotype.Repository;
@Repository
public class UserAndAddress implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Integer sex;
/**
* 配置①begin...
* 常用的(1:N)配置(无法解决N+1问题),测试时请根据具体的测试方法注释以下部分
* (测试UserAndAddressServiceTest内的testTr2方法时请注释以下部分)
* 注:本人在这里没有用List的返回类型。(个人意见:) 用set是因为对持久层的东西来说,最好让pojo唯一,以防脏数据,
* 在hibernate中用得最多的就是set了。但这样做很麻烦,不知道是否可取,欢迎拍砖。
*
* */
private Set<Address> addresses;
public Set<Address> getAddresses() {
return addresses;
}
public void setAddresses(List<Address> addresses) {
this.addresses =new HashSet<Address>(addresses);
}
/**配置①end**/
/***
// * 配置②begin...
// * 避免N+1(1:N、M:N)问题的例子begin******
// * (测试UserAndAddressServiceTest内的testTr1方法时请注释以下部分)
//// * ****/
// private List<Address> addresses = new MyArrayList<Address>(0);
//
// public List<Address> getAddresses() {
// return addresses;
// }
//
// public void setAddresses(List<Address> addresses) {
// this.addresses.addAll(addresses);
// }
/**配置②end**/
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
}
[/code]
xml
[code="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="UserAndAddress">
<typeAlias alias="userAndAddress" type="com.ibatis.sample.bean.UserAndAddress" />
<typeAlias alias="address" type="com.ibatis.sample.bean.Address" />
<resultMap id="get-user-result" class="userAndAddress">
<result property="id" column="id" />
<result property="name" column="name" />
<result property="sex" column="sex" />
<!--<result property="addresses" column="id" select="userAndAddress.getAddressByUserId" />如果启用命名空间-->
<result property="addresses" column="id" select="getAddressByUserId" />
</resultMap>
<select id="getUserAndAddress" parameterClass="userAndAddress" resultClass="userAndAddress">
select * from t_user where 1=1
<isNotEmpty prepend="AND" property="name">
name=#name#
</isNotEmpty>
<isNotEmpty prepend="AND" property="sex">
sex=#sex#
</isNotEmpty>
<isNotEmpty prepend="AND" property="id">
id=#id#
</isNotEmpty>
</select>
<select id="searchUserAndAddress" parameterClass="userAndAddress"
resultMap="get-user-result">
select * from t_user
<dynamic prepend="WHERE">
<isNotEmpty prepend="AND" property="name">
name=#name#
</isNotEmpty>
<isNotEmpty prepend="AND" property="sex">
sex=#sex#
</isNotEmpty>
<isNotEmpty prepend="AND" property="id">
id=#id#
</isNotEmpty>
</dynamic>
</select>
<select id="getAddressByUserId" parameterClass="Integer"
resultClass="address">
select
address,
zipcode
from t_address
where user_id = #userid#
]]>
<!--重复部分省了。。。。。-->
[/code]
javaBean
[code="java"]
package com.ibatis.sample.bean;
import org.springframework.stereotype.Repository;
/**
* @author summerPine(沙漠派)
*
* email:xnxqs@163.com
* QQ:254120499
* MSN:xnxqs@hotmail.com
* 2009-7-20 下午02:13:18
* ibatisTest
* 转载请保留! ^_^
*
*creat sql
*if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[t_address]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[t_address]
GO
CREATE TABLE [dbo].[t_address] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[address] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[zipcode] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[user_id] [int] NULL
) ON [PRIMARY]
GO
*/
@Repository
public class Address {
String address;
String zipcode;
int id;
//无法实现双向,下面这个属性其实没用上。按ibatis的refence推荐:写二个address。一个带UserAndAddress ,一个不带。
UserAndAddress userAndAddress;
public UserAndAddress getUserAndAddress() {
return userAndAddress;
}
public void setUserAndAddress(UserAndAddress userAndAddress) {
this.userAndAddress = userAndAddress;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
[/code]
通用DAO接口:
[code="java"]
package com.ibatis.sample.dao;
import java.io.Serializable;
import java.util.List;
public interface IModelDao {
public ID create(T value);
public int update(T value);
public int delete(T value);
public List getObjects(T value);
public T getObjectById(T value);
public List getAnyObjects(String str,Object entity);
}
[/code]
通用DAO实现
[code="java"]
package com.ibatis.sample.dao;
import java.io.Serializable;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ibatis.sample.comm.Util;
/**
* @author summerPine(沙漠派)
*
*
* email:xnxqs@163.com
* QQ:254120499
* MSN:xnxqs@hotmail.com
* 2009-7-15 下午04:00:31
* ibatisTest
* 转载请保留! ˆ_ˆ;
*
* [color=red]注二[/color]:
* 模式DAO,实际应用中只用这一个DAO即可。 继承BaseDao是为了注入sqlmapclient
* 至于为什么要实现IModelDao这样的一个接口基于以下原因: 1.为了简化配置,只用一种代理(JDK的动态代理机制),
* (如果系统对性能要求比较高,并发性较高的话,建议采用CGLIB方式产生代理实例,
* 具体这方面的配置请参阅spring文档,并加上CGLIB包。)
*
* 注:因为本Dao只是一个例子,所以只写了最基本的CRUD,其实本可以扩展得更多的,
* 但太麻烦了,本人将在后期奉上。至于有的朋友可能会问到有没有HIBERNATE的通用包,
* 在这里帮白衣兄打打广告以视支持:强烈推荐去观看springSide的DAO部分的源码
*
*/
// 另,关于spring的事务控制问题,spring文档上说:
//
// “请注意Spring框架的事务基础架构代码将默认地 只 在抛出运行时和unchecked exceptions时才标识事务回滚。 也就是说,当抛出一个
// RuntimeException 或其子类例的实例时。(Errors 也一样 - 默认地 - 标识事务回滚。)从事务方法中抛出的Checked
// exceptions将 不 被标识进行事务回滚。”
// 在这里,我一起有一个疑问就是,要不要在DAO层抛出异常??抛出什么样的异常为好?(针对spring2.5)
// 目前本人的做法就是DAO层不管,在service层捕捉Uncheck异常,抛出一个自定义的runtimeException,然后在UI层捕捉错误。理由:
1、这是个通用DAO,有异常也属于不可复的底层异常。把这种底层异常交给service来处理,可以根据实际情况把这种异常包装一下,并抛给UI层一个对用户来说有意义的异常。(比如说删除时,如果ID不存在,其实是不会报错的,但我可以包装一下,然后交给ui层,提示ID不存在,再比如说针对一些不可恢复的异常,我们也可以包装一下,以便让程序继续走下去。)
2、理由二,看了javaeye上一位大大写的《关于j2ee的异常处理。。》报歉,本人记不清全称了和作者了,上面也是这样推荐的。
不知道可不可取?请来者拍砖并给出理由。
// 这里加上service是为了给懒人准备的,有了它就可以少写一个跟实体类相关的dao层了。可以直接在service层用了。
@Service
public class IbatisDao extends BaseDao implements
IModelDao {
private static Log logger = LogFactory.getLog(IbatisDao.class);
//如果sql map的xml中存在重复的方法,可以考虑启用命名空间 eg. namespce.getUser();
// private String BeanNameSpace = getPersistentClass().getName()+".";
// 常用操作的命名规范为: SQL_操作命+实例类型名称,
// 比如说实例 u是User类型,现在要在数据库内添加 一行记录那么SQL_Add+Util.getTName(entity)
// 返回原就是addUser字符串
private final static String SQL_Add = "add";
private final static String SQL_DELETE = "delete";
private final static String SQL_UPDATE = "update";
private final static String SQL_Get = "get";
private final static String SQL_SEARCH = "search";
// 保持实体对象类的类型
private Class persistentClass;
public void setPersistentClass(Class persistentClass) {
this.persistentClass = persistentClass;
}
protected Class getPersistentClass() {
return persistentClass;
}
// 觉得这个带参的构造函数还是很有必要的,多一个有备无患嘛,虽然在我的应用里面看不出它的作用。
@SuppressWarnings("unchecked")
public IbatisDao(Class clazz) {
this.persistentClass = clazz;
}
// 有了上面带参的construct,这里必须再写一个无参的construct否则代理类会找不到构造函数,无 法注入了。
public IbatisDao() {
super();
}
/*
* (non-Javadoc)
*
* @see com.ibatis.sample.dao.IModelDao#create(java.lang.Object)
*/
@SuppressWarnings("unchecked")
public ID create(T entity) {
logger.info("正在添加对象" + entity.getClass().getName());
ID id = (ID) getSqlMapClientTemplate().insert(
SQL_Add + Util.getTName(entity), entity);
if (id != null)
logger.info("添加成功!");// 在这里不做判断直接写,会不会有什么问题?
return id;
}
public int delete(T entity) {
logger.info("正在删除对象" + entity.getClass().getName());
int rows = getSqlMapClientTemplate().delete(
SQL_DELETE + Util.getTName(entity), entity);
if (rows != 0)
logger.info("删除成功!");
return rows;
}
@SuppressWarnings("unchecked")
@Transactional(readOnly = true)
// 查询语句一律不通过事务,以减少资源 损耗,加快速度。
public T getObjectById(T entity) {
logger.info("正在获取对象" + entity.getClass().getName());
entity = (T) getSqlMapClientTemplate().queryForObject(
SQL_Get + Util.getTName(entity), entity);
if (entity != null)
logger.info("获取成功!");
return entity;
}
@SuppressWarnings("unchecked")
@Transactional(readOnly = true)
// 采取这种方法搜索对象时,如果想获得表内所有记录,应该传与一个空的实例,比如说 new User()
public List getObjects(T entity) {
logger.info("正在获取对象列表" + entity.getClass().getName());
List list = getSqlMapClientTemplate().queryForList(
SQL_SEARCH + Util.getTName(entity), entity);
if (list != null && list.size() > 0)
logger.info("获取对象列表成功!");
return list;
}
@SuppressWarnings("unchecked")
// @Transactional(readOnly = true)//
// 如果要用上本方法必须先设置persistentClass,eg.调用setpersistentClass();
//但这种写法不是很好。会让人莫名 其妙为什么调用 setpersistentClass。建议在实际开发中多写一条可以查询所有对象的maping语句。
public List getAllObjects() {
T t=null;
try {
t = persistentClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (t == null)
return null;
else
return getObjects(t);
}
@SuppressWarnings("unchecked")
@Transactional(readOnly = true)
// 采取这种方法搜索对象时,如果想获得表内所有记录,应该传与一个空的实例,比如说 new User()
public List getAnyObjects(String str,Object entity) {
logger.info("正在获取对象列表" + entity.getClass().getName());
List list = getSqlMapClientTemplate().queryForList(str, entity);
if (list != null && list.size() > 0)
logger.info("获取对象列表成功!");
return list;
}
public int update(T entity) {
logger.info("正在更新对象" + entity.getClass().getName());
int rows = getSqlMapClientTemplate().update(
SQL_UPDATE + Util.getTName(entity), entity);
if (rows > 0)
logger.info("更新成功!");
return rows;
}
}
[/code]
基础service的接口
[code="java"]
package com.ibatis.sample.service;
import java.io.Serializable;
import com.ibatis.sample.dao.IModelDao;
//service层的基类,主要是为了得到dao,有了它,就算把DAO层改得一埸湖涂也方便以后扩展,
//我现在的单位就因为以前的东西写得太死,所以好多项目的维护已经惨不忍睹了。这里再次深刻体会到分层的好处。
public interface BaseService{
public void setIbatisDao(IModelDao modelDao);
public IModelDao getIbatisDao();
}
[/code]
[color=red]注:[/color]
具体业务(service)层的接口
我在这里把service层直接当业务层,不知行不行?有时个人觉得service上面可以再发一个biz层出来专门跟业务打交道,不知道那种更可取,请拍砖。。
[code="java"]
package com.ibatis.sample.service;
import com.ibatis.sample.bean.UserAndAddress;
public interface IUserAndAddressService extends BaseService{
public void printUserAndAddress();
public void printUserAndAddressQ();
}
[/code]
实现类
[code="java"]
package com.ibatis.sample.service.impl;
import java.util.List;
import javax.annotation.Resource;
import javax.el.MethodInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ibatis.sample.bean.Address;
import com.ibatis.sample.bean.UserAndAddress;
import com.ibatis.sample.bean.UserAndAddress1;
import com.ibatis.sample.comm.excep.ServiceException;
import com.ibatis.sample.dao.IModelDao;
import com.ibatis.sample.service.IUserAndAddressService;
/**
* @author summerPine(沙漠派)
*
* email:xnxqs@163.com
* QQ:254120499
* MSN:xnxqs@hotmail.com
* 2009-7-17 下午03:30:58
* ibatisTest
* 转载请保留! ^_^
*
*一对多的测试,为了跟让大家看得更方便点,不影响userService的测试。就跟UserService分开写了。
*/
@Service
public class UserAndAddressService implements IUserAndAddressService {
private IModelDao ibatisDao;
public IModelDao getIbatisDao() {
return ibatisDao;
}
@Resource
public void setIbatisDao(IModelDao modelDao) {
this.ibatisDao = modelDao;
}
// @Transactional
public void printUserAndAddress() throws ServiceException{
try {
List list=ibatisDao.getObjects(new UserAndAddress());
if(list !=null)
for(UserAndAddress ua:list){
System.out.println("用户:"+ua.getName()+"的住址是:");
for(Address ad:ua.getAddresses()){
System.out.println(" "+ad.getAddress());
}
}
} catch (Exception e) {
throw new ServiceException("查询失败",e);
}
}
//换个方法取得用户名和地址,如果成功速度较快。
public void printUserAndAddressQ() throws ServiceException{
try {
List list=ibatisDao.getAnyObjects("getUserAddress",new UserAndAddress1());
if(list !=null)
for(UserAndAddress ua:list){
System.out.println("用户:"+ua.getName()+"的住址是:");
for(Address ad:ua.getAddresses()){
System.out.println(" "+ad.getAddress());
}
}
} catch (Exception e) {
throw new ServiceException("查询失败",e);
}
}
}
[/code]
测试方法:
[code="java"]
package com.ibatis.sample.test;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ibatis.sample.service.IUserAndAddressService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserAndAddressServiceTest {
@Resource //spring推荐用注解,与@Autowired相比可更少 的依赖spring,不过这个注解是根据name来注入的。
IUserAndAddressService userAndAddressService;
@Test
public void testTr() {
try {
userAndAddressService.printUserAndAddress();
} catch (Exception e) {
e.printStackTrace();
}
}
// @Test 测试1:n的N+1问题,暂时没法实现。
public void testTr2() {
try {
userAndAddressService.printUserAndAddressQ();
} catch (Exception e) {
e.printStackTrace();
}
}
}
[/code]
sql-map-config.xml
[code="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">
<!--
当userStatementNamespaces为false时,要注意映射文件中,Statement定义无重名。
-->
<!-- typeAlias alias="mapBean" type="com.vsc.po.MapBean" / -->
<!--<transactionManager type="JDBC">
<dataSource type="SIMPLE">
<property name="JDBC.Driver"
value="com.microsoft.jdbc.sqlserver.SQLServerDriver" />
<property name="JDBC.ConnectionURL"
value="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=rbac;SelectMethod=Cursor" />
<property name="JDBC.Username" value="sa" />
<property name="JDBC.Password" value="sa" />
<property name="Pool.MaximumActiveConnections" value="10" />
<property name="Pool.MaximumIdleConnections" value="5" />
<property name="Pool.MaximumCheckoutTime" value="120000" />
<property name="Pool.TimeToWait" value="500" />
<property name="Pool.PingQuery" value="select 1 T_user" />
<property name="Pool.PingEnabled" value="false" />
<property name="Pool.PingConnectionsOlderThan" value="1" />
<property name="Pool.PingConnectionsNotUsedFor" value="1" />
</dataSource>
</transactionManager>-->
<!-- sqlMap resource="com/ibatis/sample/bean/UserAndAddress1.xml"/-->
[/code]
Srpring.xml
[code="xml"]
<?xml version="1.0" encoding="UTF-8"?>
classpath:DB.properties
<!--<bean id="userDao" class="com.ibatis.sample.dao.impl.UserDao">
<property name="dataSource" ref="dataSource" />
<property name="sqlMapClient" ref="sqlMapClient" />
</bean>
-->
<!-- a PlatformTransactionManager is still required -->
<!-- (this dependency is defined somewhere else) -->
[/code]
写到这里,扩展测试中的前三个目的已经基本上实现了。下面帖部分解决1:N中n+1的实现思路(不可实现)
1、改写ArrayList
[code="java"]
package com.ibatis.sample.comm;
import java.lang.reflect.ParameterizedType;
public class MyArrayList extends java.util.ArrayList {
/**
*
*/
private static final long serialVersionUID = -5105729373313535708L;
Class cls = null;
@SuppressWarnings("unchecked")
public MyArrayList() {
super();
//利用反射获得当前类型。
if (cls == null) {
ParameterizedType pt = (ParameterizedType) getClass()
.getGenericSuperclass();
cls = (Class) pt.getActualTypeArguments()[0];
}
}
@SuppressWarnings("unchecked")
public MyArrayList(int i) {
super(i);
if (cls == null) {
ParameterizedType pt = (ParameterizedType) getClass()
.getGenericSuperclass();
cls = (Class) pt.getActualTypeArguments()[0];
}
}
public MyArrayList(Class cls) {
super();
this.cls = cls;
}
public MyArrayList(Class cls,int i) {
super(i);
this.cls = cls;
}
@Override
public T get(int index) {
//当所取索引=其集合类大小时,就自动在集合类里现添加一个实体类。
if (cls != null && index==this.size()) {
try {
add((T) cls.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return super.get(index);
}
}
[/code]
改写javaBean
[code="java"]
/***
* 配置②begin...
* 避免N+1(1:N、M:N)问题的例子begin******
* (测试UserAndAddressServiceTest内的testTr1方法时请注释以下部分)
// * ****/
private List addresses = new MyArrayList(0);
public List getAddresses() {
return addresses;
}
public void setAddresses(List addresses) {
this.addresses.addAll(addresses);
}
/**配置②end**/
[/code]
配置文件:
[code="xml"]
<!--
ibatis有个最大的缺陷就是无法解决1:n、M:n的N+1问题(1:1的N+1问题,指南上有解决方案,这里就不重复了。)
对于1:n、M:n的N+1问题本人有个推理解决方案(没有实践过),(以user 1: address N为例)但有几个使用限制。
1.注释UserAndAddress类中的配置①部分。 2.更改数据库连接
3.重写ArrayLIst,重载其中的get方法。见本例中的。com.ibatis.sample.comm.MyArrayList
4.本方法目前只对oracle数据库有效(利用了伪列)。
这里的用户和地址是一对多的关系,用下面getUserAndAddress这种方式取出时会有N+1的问题,现在为了避免N+1换种方法
-->
<!--
双向的1:N、M:N暂时有问题,只能是如指南上所说:
重要提示!目前SQL Map架构无法自动解决resultMap之间的双向关系。
这在处理“父/子” 双向关系的resultMap时尤其要注意。
一个简单的办法是,为其中一种情况再定义一个不装入父对象的resultMap(反之亦然
所以下面这行就不写了
-->
<!--<result property="addresses.zipcode" column="id"
select="UserAndAddress1.getAddressByUserId" />-->
select t.rownums-1 as indexs,t.id,t.name,
t.sex,t.addressId,t.address,t.zipcode,t.user_id
from (select rownum as rownums, t_user.id,t_user.name,
t_user.sex,t_address.id as addressId,
t_address.address,t_address.zipcode,
t_address.user_id
from t_user left outer join t_address on t_user.id =user_id ) t;
<!--如有需要,可继续加检索条件。
-->
[/code]
至此全文结束。其实本人对ibatis确实不熟,以前用的基本都hb。现在用了ibatis还是觉得ibatis确实有它的可取之处,但烦人的1:N,N:m外加双向关联,解决起来确实太麻烦,不知道各位在日常 的开发应用中是如何实现的。难道都是在需要的时候才去再次检索?或者干脆把性能问题抛开到一边,能实现关联就行??欢迎讨论,有砖尽管拍,但请一定记住了:强烈BS光拍砖不给油(理由)的人~~ ^_^!!!
附件是源码。用myeclipse7.5打开就能用了,加上sql驱动就能用了。包里面有些是struts的包,是本人准备整合用的,但暂时没用上,可以删除。表的话,还请自己建,也就二个表,并且 我还给出了sql语句不是吗(在javabean的注释部分)?做人要勤快。呵呵。。]]>
为什么标签不起作用。谁能告诉我????????
分享到:
- 2009-07-20 16:38
- 浏览 2209
- 评论(0)
- 论坛回复 / 浏览 (0 / 3780)
- 查看更多
相关推荐
9.9. 常见问题的解决方法 9.9.1. 对一个特定的 DataSource 使用了错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 ...
9.9. 常见问题的解决方法 9.9.1. 对一个特定的 DataSource 使用了错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 ...
9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1. 简介 ...
内容概要:本文详细介绍了基于松下AFPX-C38AT PLC平台的双切刀三边封制袋机控制系统。该系统通过PLC控制四台伺服电机进行切刀和移刀动作以及二轴送袋定位,同时管理两台变频器实现主机和放料电机的同步调速,并利用WK8H模块进行16路温控输出。文中展示了具体的PLC编程实例,如伺服电机的DRVI指令、变频器的同步控制、温控模块的PID调节等。此外,还讨论了硬件配置、触摸屏界面设计、通信协议设置等方面的内容,强调了系统的灵活性和稳定性。 适合人群:从事工业自动化控制领域的工程师和技术人员,尤其是对PLC编程和伺服电机控制感兴趣的读者。 使用场景及目标:适用于需要深入了解PLC控制系统的开发人员,帮助他们掌握伺服电机控制、变频器同步调速和温控模块编程的具体方法,提高实际项目中的应用能力。 其他说明:文章不仅提供了详细的编程示例,还分享了许多实际调试的经验和技巧,有助于读者更好地理解和应用相关技术。
计算机审计软件的特点与应用.pdf
离散傅里叶变换(DFT)分析 函数[F,FT,Phase]=DFT(T,Signal,Fi,FF,Res,P,Cursor)计算离散傅里叶变换(DFT) 功能概述:离散傅立叶变换(DFT)分析 函数[F,FT,Phase]=DFT(T,Signal,Fi,FF,Res,P,Cursor)是频率域信号分析的通用工具。它在指定的频率范围内计算信号的离散傅立叶变换(DFT),提供可定制的可视化选项。 输入 T(采样时间向量,秒):表示与正在分析的信号样本相对应的时间点。 信号:您希望在频域中检查的数据集或信号。 FI(以赫兹为单位的初始频率):频率分析的起点。 FF(最终频率(Hz):频率分析范围的上限。 Res(分辨率以赫兹为单位):确定傅立叶变换的精度。较小的值会增加分辨率。 P(打印选项): 0:没有生成图。 1: 仅显示震级图。 2: 显示大小和相位图。 光标(在绘图上启用光标)(可选): 1: 当P不
内容概要:本文详细介绍了如何在Matlab中构建一个综合了垃圾焚烧、碳捕集和电转气(P2G)技术的虚拟电厂优化调度系统。该系统旨在通过合理的设备参数设置、多能流耦合约束以及分段碳价机制的目标函数设计,实现环保与经济效益的最大化。文中展示了具体的数学模型建立方法,如设备参数初始化、能量平衡约束、碳捕集与P2G物料平衡、分时碳成本计算等,并讨论了求解技巧,包括变量定义、求解器选择和约束条件处理等方面的内容。此外,还探讨了垃圾焚烧发电占比变化对P2G设备启停策略的影响,以及不同时间段内的最优调度策略。 适合人群:从事能源系统优化研究的专业人士,特别是那些熟悉Matlab编程并希望深入了解虚拟电厂调度机制的人群。 使用场景及目标:适用于希望提高虚拟电厂运行效率的研究机构或企业。通过本项目的实施,能够更好地理解如何整合多种能源技术,在满足电力供应需求的同时减少碳排放,降低成本。具体应用场景包括但不限于:制定更加科学合理的发电计划;评估新技术引入后的潜在效益;探索不同政策环境下的最佳运营模式。 其他说明:文中提到的一些关键技术点,如碳捕集与P2G的协同工作、垃圾焚烧发电的灵活应用等,对于推动清洁能源的发展具有重要意义。同时,作者也在实践中遇到了一些挑战,如约束条件之间的冲突等问题,并分享了解决这些问题的经验。
入栈和出栈的基本操作
内容概要:本文详细探讨了V型永磁同步电机中永磁体参数调整的方法和技术,特别是在Maxwell软件中的应用。首先介绍了V型永磁体的关键参数(如V型夹角、磁钢厚度、极弧系数等)及其对电机性能的影响。接着讨论了利用Maxwell进行参数化建模、参数扫描、优化方法(如响应面法、多目标遗传算法)的具体步骤和注意事项。文中还提供了多个实用脚本,涵盖从几何建模、材料属性设置到求解器配置、后处理分析等多个方面。此外,强调了优化过程中应注意的问题,如退磁校验、磁密饱和、涡流损耗等,并给出了一些实战技巧。 适合人群:从事电机设计与仿真的工程师、研究人员,尤其是熟悉Maxwell软件的用户。 使用场景及目标:帮助用户掌握V型永磁同步电机永磁体参数调整的技术要点,提高电机性能指标(如降低齿槽转矩、减少谐波失真、优化转矩波动等)。通过实例和脚本指导,使用户能够在Maxwell中高效地完成仿真和优化任务。 其他说明:文章不仅提供了详细的理论解释,还包括大量实践经验分享和常见问题解决方案,有助于读者更好地理解和应用相关技术。
内容概要:本文详细介绍了光伏发电系统的仿真建模及其控制策略。主要内容分为四个部分:首先是光伏发电系统仿真模型的搭建,通过数学公式和Python代码实现了太阳电池特性的模拟;其次,探讨了扰动观察法(PO)作为最大功率点跟踪(MPPT)的方法,展示了其实现逻辑和代码示例;第三部分讨论了带储能控制策略的设计,利用状态机管理储能系统的充放电过程,确保电力供应平稳;最后进行了负载突变验证实验,评估了系统在极端条件下的稳定性和可靠性。通过这些步骤,作者不仅解释了理论背景,还提供了具体的实现细节和技术挑战。 适合人群:对光伏发电系统感兴趣的研究人员、工程师以及相关领域的学生。 使用场景及目标:适用于希望深入了解光伏发电系统工作原理的人群,尤其是关注最大功率点跟踪技术和储能控制系统设计的应用开发者。目标是帮助读者掌握光伏系统仿真的关键技术,为实际项目提供理论支持和技术指导。 其他说明:文中提供的代码片段可以直接用于实验环境,便于读者动手实践。此外,针对可能出现的问题如耦合振荡等,给出了相应的解决方案。
内容概要:本文详细介绍了8极48槽辐条型电机转子桥的参数化建模方法及其优化过程。通过将桥的厚度、过渡圆弧半径和倒角角度作为变量进行参数化处理,利用Maxwell软件实现了自动化仿真和优化。文中展示了具体的Python和VBScript代码示例,用于动态调整桥部尺寸并监控磁密分布,最终通过参数扫描找到最佳设计参数组合,显著降低了磁密峰值和扭矩波动,提高了电机的整体性能。 适合人群:从事电机设计与仿真的工程师和技术人员,尤其是熟悉Maxwell软件的用户。 使用场景及目标:适用于需要优化电机转子桥结构的设计项目,旨在提高电机性能,降低磁密峰值和扭矩波动,确保机械强度的同时提升电磁性能。 其他说明:文章提供了详细的代码示例和操作步骤,帮助读者快速掌握参数化建模技巧,并强调了网格设置和多参数联动优化的重要性。
内容概要:本文详细介绍了用于风电调频并网系统的4机2区模型,该模型能够在短时间内完成长时间跨度的仿真,极大提高了科研和工程分析的效率。文中具体阐述了模型的结构特点,包括两个区域内的发电机组分布、连接方式以及风电场的虚拟惯量控制机制。此外,文章深入解析了四种PSS(电力系统稳定器)模式的工作原理及其在不同工况下的表现,特别是针对风电接入带来的低频振荡问题进行了讨论。通过实例展示了PSS模式对系统稳定性的显著提升效果,并分享了一些实用的调参技巧。 适合人群:从事电力系统仿真、风电并网研究的专业技术人员及高校相关专业师生。 使用场景及目标:适用于需要进行大规模风电调频并网系统仿真的场合,旨在帮助研究人员更好地理解和解决风电接入对电网稳定性的影响,优化风电并网友好度。 其他说明:文章不仅提供了理论分析,还包括具体的Python和Matlab代码示例,便于读者理解和实践。同时强调了在高风电渗透率条件下选择合适PSS模式的重要性。
内容概要:本文详细介绍了如何使用LabVIEW的Excel工具包来高效生成带有特定格式的测试报告。首先,准备一个Excel模板文件,设置好表头样式、公司LOGO和合并单元格,并用特殊标记占位。然后,通过LabVIEW代码进行Excel操作,如初始化Excel应用、打开和复制模板文件、写入测试数据、设置条件格式、调整列宽以及保存和关闭文件。文中强调了使用二维数组批量写入数据、条件格式设置超标数据标红、精确控制列宽、避免文件覆盖等问题。此外,还提到了一些常见问题及其解决方案,如Excel进程卡死、数据错位等。最终,通过这些方法可以将原本复杂的报告生成过程大幅简化,提高工作效率。 适合人群:熟悉LabVIEW编程的工程师和技术人员,尤其是从事自动化测试和数据分析工作的人员。 使用场景及目标:适用于需要频繁生成格式一致的测试报告的场景,如汽车电子测试、环境监测等领域。目标是通过LabVIEW的Excel工具包实现自动化、高效的报告生成,节省时间和精力。 阅读建议:读者可以通过本文学习如何利用LabVIEW的Excel工具包快速生成带格式的测试报告,掌握关键技术和最佳实践,从而提升工作效率。同时,在实践中应注意模板的设计和代码的优化,以应对各种复杂的需求变化。
main (4).ipynb
计算机数学基础(下).pdf
内容概要:本文详细介绍了如何利用MATLAB实现基于多智能体系统一致性算法的电力系统分布式经济调度策略。首先,通过构建邻接矩阵生成函数,处理电网拓扑结构,确保每个节点能够正确获取邻居信息。接着,定义发电机成本函数和负荷效用函数,将两者统一为二次函数形式,以便更好地兼顾发电侧和用电侧的经济性。然后,重点展示了核心的一致性迭代算法,通过拉普拉斯矩阵实现信息扩散,使发电机和负荷之间的增量成本和效益逐步趋于一致。此外,文中还提供了具体的测试案例,包括10台发电机和19个柔性负荷组成的系统,展示了算法的高效性和鲁棒性。最后,强调了通信拓扑设计对收敛速度的影响,并分享了一些调试经验和潜在的应用前景。 适合人群:电力系统研究人员、自动化控制工程师、MATLAB开发者以及对分布式优化算法感兴趣的学者。 使用场景及目标:适用于电力系统经济调度的研究与开发,旨在提高调度效率、降低成本的同时保障系统的稳定性。通过分布式算法替代传统的集中式调度方式,增强系统的隐私保护能力和计算效率。 其他说明:文中提供的MATLAB代码不仅可用于学术研究,还可以进一步应用于实际工程项目中,特别是在含有大量新能源接入的现代电力系统中,展现出更大的优势。
计算机数控装置课件.pdf
内容概要:本文详细介绍了RRT(快速扩展随机树)路径规划算法的多个优化方法及其具体实现。首先指出原始RRT存在的缺陷,如路径质量差、计算时间长等问题。然后提出了一系列改进措施,包括目标偏向采样、自适应步长控制、路径平滑处理以及椭圆约束采样等。每个改进都附有具体的Python代码片段,并解释了其实现思路和技术细节。此外,文中还讨论了不同改进方案之间的协同使用效果,强调了实际应用中的注意事项。 适合人群:从事机器人路径规划研究的技术人员,尤其是有一定编程基础并希望深入了解RRT算法优化的人群。 使用场景及目标:适用于各种需要高效路径规划的应用场合,如仓储机器人、无人机避障、机械臂运动规划等。主要目标是提高路径规划的速度和质量,同时减少计算资源消耗。 其他说明:尽管这些改进显著提升了RRT的表现,但在实际部署时仍需考虑传感器噪声和系统延迟等因素的影响。作者分享了许多个人实践经验,为读者提供了宝贵的参考。
计算机试题实例分析.pdf
内容概要:本文详细介绍了利用三菱FX3U系列PLC构建自动门禁系统的全过程。首先阐述了硬件配置方案,包括选用三菱FX3U-32MT作为主控制器,配备多种传感器如红外对射、地磁以及防夹传感器等,并采用适当的执行机构进行门的开闭控制。接着深入解析了梯形图逻辑的设计,涵盖基本开闭逻辑、安全回路设计、滤波处理等方面的内容。文中特别强调了几个关键技术点,如通过定时器控制门的开启时间和防夹保护措施,解决了红外传感器误触发的问题,并引入了GX Works2模拟器用于程序调试。此外,还讨论了如何通过RS485通信接口实现身份验证模块的联网功能及其故障转移机制。最后,作者分享了一些实用的经验教训,例如避免信号干扰的方法和确保系统稳定性的冗余设计。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对PLC编程有一定基础的人群。 使用场景及目标:适用于需要构建高效可靠的自动门禁系统的场合,旨在提高门禁系统的安全性、可靠性和智能化水平。 其他说明:文中提到的具体案例和解决方案可以为类似项目的实施提供宝贵的参考价值。同时,作者还提供了许多调试技巧和注意事项,有助于读者更好地理解和应用所学知识。