论坛首页 Java企业应用论坛

让你的 Ibatis2 也支持Annotation

浏览 23947 次
精华帖 (0) :: 良好帖 (5) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-10-10   最后修改:2009-01-16
在支持xml配置方式的基础上增加了对annotation的支持,用户可以根据自己的喜好来选择或者两种方式并存。详情请大家看:http://www.rest4g.org/viewthread.php?tid=12&extra=page%3D1

代码示例如下:
Account.java
package org.jrest4guice.persistence.ibatis;
public class Account {
  private int id;
  private String firstName;
  private String lastName;
  private String emailAddress;

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public String getEmailAddress() {
    return emailAddress;
  }

  public void setEmailAddress(String emailAddress) {
    this.emailAddress = emailAddress;
  }

}
AccountService.java
package org.jrest4guice.persistence.ibatis;
import java.sql.SQLException;
import java.util.List;
import org.jrest4guice.persistence.ibatis.annotations.Delete;
import org.jrest4guice.persistence.ibatis.annotations.IbatisDao;
import org.jrest4guice.persistence.ibatis.annotations.Insert;
import org.jrest4guice.persistence.ibatis.annotations.Result;
import org.jrest4guice.persistence.ibatis.annotations.ResultMap;
import org.jrest4guice.persistence.ibatis.annotations.Select;
import org.jrest4guice.persistence.ibatis.annotations.Update;
import org.jrest4guice.transaction.annotations.Transactional;
import org.jrest4guice.transaction.annotations.TransactionalType;

import com.google.inject.Inject;
import com.ibatis.sqlmap.client.SqlMapClient;

@IbatisDao
@SuppressWarnings("unchecked")
@Transactional
@ResultMap(id = "accountResultMap", result = {
		@Result(property = "id", column = "id"),
		@Result(property = "firstName", column = "firstName"),
		@Result(property = "lastName", column = "lastName"),
		@Result(property = "emailAddress", column = "emailAddress") }, resultClass = Account.class)
@Cachemodel(id = "account-cache", flushInterval = "24", flushOnExecute = {
		"insertAccount", "updateAccount", "deleteAccount" }, type = "LRU", 
		property = { @Property(name = "size", value = "100") })
public class AccountService {
	@Inject
	private SqlMapClient sqlMapper;

	@Select(id = "selectAllAccounts", sql = "select * from ACCOUNT", 
			resltMap = "accountResultMap", cacheModel = "account-cache")
	@Transactional(type = TransactionalType.READOLNY)
	public List<Account> findAll() throws SQLException {
		return sqlMapper.queryForList("selectAllAccounts");
	}

	@Select(sql = "select id ,firstName,lastName,emailAddress from "
			+ "ACCOUNT where id = #id#")
	@Transactional(type = TransactionalType.READOLNY)
	public Account getAccountById(int id) throws SQLException {
		return (Account) sqlMapper.queryForObject("getAccountById", id);
	}

	@Insert(id = "insertAccount", sql = "insert into ACCOUNT (id,firstName,"
			+ "lastName,emailAddress) values (#id#, #firstName#, #lastName#, "
			+ "#emailAddress#)")
	public void createAccount(Account account) throws SQLException {
		sqlMapper.insert("insertAccount", account);
	}

	@Update(sql = "update ACCOUNT set firstName = #firstName#,lastName = "
			+ "#lastName#,emailAddress = #emailAddress# where id = #id#")
	public void updateAccount(Account account) throws SQLException {
		sqlMapper.update("updateAccount", account);
	}

	@Delete(id = "deleteAccount", sql = "delete from ACCOUNT where id = #id#")
	public void deleteAccount(int id) throws SQLException {
		sqlMapper.delete("deleteAccount", id);
	}

	@Select(id = "queryAccounts", 
		sql = "select * from ACCOUNT "
			+ "<dynamic prepend=\"where\">"
			+ " <isNotNull prepend=\"and\" property=\"firstName\">"
			+ "    firstName = #firstName#" 
			+ " </isNotNull>"
			+ " <isNotNull prepend=\"and\" property=\"lastName\">"
			+ "    lastName = #lastName#" 
			+ " </isNotNull>"
			+ " <isNotNull prepend=\"and\" property=\"emailAddress\">"
			+ "    emailAddress = #emailAddress#" 
			+ " </isNotNull>"
			+ "</dynamic> " 
			+ "order by lastName", resltMap = "accountResultMap", 
			cacheModel = "account-cache")
	@Transactional(type = TransactionalType.READOLNY)
	/**
	 * 动态SQL查询
	 */
	public List<Account> queryAccounts(Account account) throws SQLException {
		return sqlMapper.queryForList("queryAccounts",account);
	}
}
AccountServiceTest.java
package org.jrest4guice.persistence.ibatis;

import java.sql.SQLException;
import java.util.List;
import junit.framework.Assert;
import org.jrest4guice.guice.GuiceContext;
import org.jrest4guice.guice.PersistenceGuiceContext;
import org.junit.BeforeClass;
import org.junit.Test;

public class AccountServiceTest {
	private static AccountService service;

	@BeforeClass
	public static void setUp() throws Exception {
		// 初始化JRest4Guice
		PersistenceGuiceContext.getInstance().useIbatis(
				"org.jrest4guice.persistence.ibatis").init();
		// 获取服务
		service = GuiceContext.getInstance().getBean(AccountService.class);
	}

	@Test
	public void doTest() {
		List<Account> accounts;
		try {
			Account account = new Account();
			account.setFirstName("张");
			account.setLastName("学友");
			account.setEmailAddress("jackey@rest4g.org");
			// 添加
			service.createAccount(account);

			account = new Account();
			account.setFirstName("刘");
			account.setLastName("学友");
			account.setEmailAddress("test@rest4g.org");
			// 添加
			service.createAccount(account);
			
			//查询(按lastName)
			Account queryCondition = new Account();
			queryCondition.setLastName("学友");
			accounts = service.queryAccounts(queryCondition);
			Assert.assertEquals(2, accounts.size());
			
			//查询(按firstName和lastName)
			queryCondition.setFirstName("张");
			accounts = service.queryAccounts(queryCondition);
			Assert.assertEquals(1, accounts.size());

			// 修改
			account = accounts.get(0);
			account.setFirstName("何");
			service.updateAccount(account);
			account = service.getAccountById(account.getId());
			Assert.assertNotNull(account);
			Assert.assertEquals("何", account.getFirstName());

			//查询所有
			accounts = service.findAll();
			Assert.assertEquals(2, accounts.size());

			// 删除
			for (Account ac : accounts){
				service.deleteAccount(ac.getId());
			}
			
			//断言删除的结果
			accounts = service.findAll();
			Assert.assertEquals(0, accounts.size());
		} catch (SQLException e) {
			Assert.fail(e.getLocalizedMessage());
		}
	}
}
   发表时间:2008-10-10  
引用
# @Select(id = "queryAccounts",  
         sql = "select * from ACCOUNT " 
             + "<dynamic prepend=\"where\">" 
             + " <isNotNull prepend=\"and\" property=\"firstName\">" 
             + "    firstName = #firstName#"  
             + " </isNotNull>" 
             + " <isNotNull prepend=\"and\" property=\"lastName\">" 
             + "    lastName = #lastName#"  
             + " </isNotNull>" 
             + " <isNotNull prepend=\"and\" property=\"emailAddress\">" 
             + "    emailAddress = #emailAddress#"  
             + " </isNotNull>" 
             + "</dynamic> "  
             + "order by lastName", resltMap = "accountResultMap",  
             cacheModel = "account-cache") 

东西是好东西,可惜把代码弄的很乱,还不如用XML呢。
0 请登录后投票
   发表时间:2008-10-10  
看到注解这么使用真觉得很可怕,代码中直接SQL还比它清楚。
0 请登录后投票
   发表时间:2008-10-10  
感觉有些画蛇添足,过犹不及阿!哈哈
0 请登录后投票
   发表时间:2008-10-10  
对于注解与配置文件的使用,我个人的看法是:对于不变的配置项采用注解,而对于可变的或者变化较多的使用xml之类的配置文件。使用注解可以和java代码紧密联系,开发时,很容易修改对象的sql,不用来回切换于java类与xml之间,使用配置文件,可以将可变的元素灵活的管理起来。
以上的实现除了对Ibatis提供了annotation的选择之外,还提供了统一的事务管理实现(通过@ Transactional来声明)
0 请登录后投票
   发表时间:2008-10-10  
等ibatis 3吧。
0 请登录后投票
   发表时间:2008-10-10  
titanfoot 写道
感觉有些画蛇添足,过犹不及阿!哈哈


你的观点很尖锐,但你的方式很真诚,那么spring 2.5为什么也提供了annotation方式,而且未来的ibatis3也会提供对annotation的支持。
0 请登录后投票
   发表时间:2008-10-10  
既然如此,Ibatis why not?
    public void deleteAccount(int id) throws SQLException {   
        sqlMapper.delete("delete from ACCOUNT where id = #id#", id);   
    } 

真怀疑Ibatis的作者为啥要提供annotation.
0 请登录后投票
   发表时间:2008-10-10  
badqiu 写道
既然如此,Ibatis why not?
    public void deleteAccount(int id) throws SQLException {   
        sqlMapper.delete("delete from ACCOUNT where id = #id#", id);   
    } 

真怀疑Ibatis的作者为啥要提供annotation.



Ibatis配置文件中定义的sql语句是可以重用的(通过id来获取),它可以是其它查询的子查询。但如果写在指定的业务方法里面就实现不了这种共享与引用。

从业务的角度来看,数据的重用不是通过sql共享来实现的,而是通过服务方法来实现,服务之间对sql是透明的,所以你以上的方式也是正确的,但这已经超出的ibatis的定义范围。你的意思呢?
0 请登录后投票
   发表时间:2008-10-10  
引用
Ibatis配置文件中定义的sql语句是可以重用的(通过id来获取)

--------
SQL ID重用那还不如写的dao方法重用。或你要重用完全可以定义一个SQL常量

String DELETE_QUERY = "delete from ACCOUNT where id = #id#"
public void deleteAccount(int id) throws SQLException { 
    sqlMapper.delete(DELETE_QUERY, id);      
}


如果Ibatis提供那么多annotation,还不如增加api方法。只留一个@ResultMap映射annotation就行了。以便查询时使用映射
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics