Simple Example of Mybatis JAVA Maven Implementation 7 – A Best Practice

In this example, we will implement a boilerplate class which takes care of common tasks like connection object, new session creation, sql mapper retrieval, transaction.

In a regular implementation, you would maintain a global SqlSessionFactory, initiated during the start of the process, reading in the database access information. For each database operation, you would

  • 1. create a new SqlSession
  • 2. perform your task(s)
  • 3. commit your changes if needed
  • 4. close out the session.

You can see a lot of repeated common tasks, except for #2. This kind of behavior naturally calls for a boilerplate implementation. So we will create an abstract class, DatabaseOperation, with an abstract method, performAction (where you would customize the specific tasks), and upon invoke, the operation object would perform the #1 through #4 jobs listed above.

package com.springriver.example.mybatis.util;

import org.apache.ibatis.session.SqlSession;

public abstract class DatabaseOperation {
	private SqlSession session;
	private boolean commitNeeded = false;
	
	public DatabaseOperation(boolean commit){
		commitNeeded = commit;
	}
	
	public DatabaseOperation(){
		this(false);
	}
	
	
	public SqlSession getSession() {
		return session;
	}

	public void setSession(SqlSession session) {
		this.session = session;
	}

	public Object invoke() {

		Object retObject = null;

		try {
			if (session == null)
				session = ConnectionFactory.getSqlSessionFactory()
						.openSession();

			retObject = performAction();

			if (commitNeeded)
				session.commit();
		} finally {

			session.close();
		}

		return retObject;
	}

	public abstract Object performAction();
}

And here is an example of how to use this boilerplate class with read operation, where commit is not needed.
ProductManager.java

	public static Product selectProductById(final int id) {
		
		DatabaseOperation op = new DatabaseOperation() {
			
			@Override
			public Object performAction() {
				ProductMapper ProductMapper = getSession().getMapper(ProductMapper.class);
				return ProductMapper.selectProductById(id);
			}
		};
		
		return (Product) op.invoke();
	}

or in a shorter form

	public static Product selectProductById(final int id) {
		
		return (Product)new DatabaseOperation() {
			
			@Override
			public Object performAction() {
				ProductMapper ProductMapper = getSession().getMapper(ProductMapper.class);
				return ProductMapper.selectProductById(id);
			}
		}.invoke();
	}

and here is how you use this class with write operation,

ProductManager

	public static void insertProduct(final Product Product) {
		
		new DatabaseOperation(true) {
			
			@Override
			public Object performAction() {
				ProductMapper ProductMapper = getSession()
						.getMapper(ProductMapper.class);
				ProductMapper.insertProduct(Product);
				return null;
			}
		}.invoke();
	}

Note in both cases, we have to use modifier “final” in the method signature, for example, public static void insertProduct(final Product Product), because we need to use that in the inter method.

Let’s make another enhancement in this implementation, using java retrospect to take care of mapper interface method invocation.

package com.springriver.example.mybatis.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.ibatis.session.SqlSession;

public abstract class DatabaseOperation {
	private SqlSession session;
	private boolean commitNeeded = false;
	
	public DatabaseOperation(boolean commit){
		commitNeeded = commit;
	}
	
	public DatabaseOperation(){
		this(false);
	}
	
	
	public SqlSession getSession() {
		return session;
	}

	public void setSession(SqlSession session) {
		this.session = session;
	}

	public Object invoke() {

		Object retObject = null;

		try {
			if (session == null)
				session = ConnectionFactory.getSqlSessionFactory()
						.openSession();

			retObject = performAction();

			if (commitNeeded)
				session.commit();
		} finally {

			session.close();
		}

		return retObject;
	}

	public abstract Object performAction();

	public Object executeMapperFunction(Class<?> mapperClass,String action, 
			Object args[])  {

		Class<?> c = mapperClass;
		Method behave = null;
		Object mapper = session.getMapper(c);
		Class<?> paramTypes[] = new Class[args.length];
		Object retObj = null;
		for (int i = 0; i < args.length; i++)
			paramTypes[i] = args[i].getClass();

		
		try {
			behave = c.getMethod(action, paramTypes);
			retObj = behave.invoke(mapper, args);
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return retObj;
	}
	
	
	public Object executeMapperFunction(Class<?> mapperClass, String operation, Object obj){
		return executeMapperFunction(mapperClass, operation, new Object[]{obj});
	}
	
	public Object executeMapperFunction( Class<?> mapperClass, String operation){
		return executeMapperFunction(mapperClass, operation, new Object[]{});
	}	
}

Here is an example of how to use this enhanced DatabaseOperation class
CategoryManager.java

package com.springriver.example.mybatis.util;

import java.util.List;

import com.springriver.example.mybatis.bean.Category;
import com.springriver.example.mybatis.bean.Product;
import com.springriver.example.mybatis.mapper.CategoryMapper;
import com.springriver.example.mybatis.mapper.ProductMapper;

public class CatgegoryManager {
	public static Category selectCategoryById(final int id) {

		return (Category)new DatabaseOperation() {
			
			@Override
			public Object performAction() {
				return executeMapperFunction(CategoryMapper.class, "selectCategoryById", id);
			}
		}.invoke();
		
	}
	
	public static Category selectCategoryDeepById(final int id) {
		return (Category)new DatabaseOperation() {
			
			@Override
			public Object performAction() {
				return executeMapperFunction(CategoryMapper.class, "selectCategoryDeepById", id);
			}
		}.invoke();
	}	
	
	public static Category selectCategoryDeepById2(final int id) {
		return (Category)new DatabaseOperation() {
			
			@Override
			public Object performAction() {
				return executeMapperFunction(CategoryMapper.class, "selectCategoryDeepById2", id);
			}
		}.invoke();
	}	
	
	public static void insertCategory(final Category category){
	
		new DatabaseOperation(true) {
			
			@Override
			public Object performAction() {
						
				executeMapperFunction(CategoryMapper.class, "insertCategory", category);
				List<Product> products = category.getProducts();
				if (products != null){
				
					for(Product product: products){
						executeMapperFunction(ProductMapper.class, "insertProduct", category);
						executeMapperFunction(CategoryMapper.class, "insertCategoryProduct", new Object[]{category.getCategoryId(), product.getProductId()});
					}
				}	
				return category.getCategoryId();
			}
		}.invoke();		
		
	}
}

Download the complete source code
springriver.mybatis.simple7

Tagged with: , ,
Posted in MyBatis
One comment on “Simple Example of Mybatis JAVA Maven Implementation 7 – A Best Practice
  1. Nice information there. Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>