从零实现MVC框架之增删改查(4)

概述

这一章节貌似有点小复杂。为了实现对象的增删改查,我们需要做点功课

1:生成id,我们采用手动生成id的方法,这里我们特意也为id创建了一个池子,所有的id都从池子里面取。

2:对象状态: 新建状态、持久状态、查询状态。查询状态是内部处理。

      处于新建状态下的对象可以进行保存操作,不能更新和删除
      处于持久状态下的对象可以进行更新和删除操作,不能保存。

3:执行器:我们所有的sql的执行都要靠执行器执行并返回结构。

4:数据装配:处理sql中的占位符以及返回结果的处理。

5:事务:提交和回滚。我们这里只是提供了这个方法,但是还没有具体实现。因为我们现在的连接都是自动提交的不涉及到事务问题。等到后面章节我们做AOP事务管理的时候会具体实现。


实现思路

为了简单起见,我们把增删改查方法都定义到实体类上。通过继承AbstractEntity可以继承这些方法。不过具体实体类不用实现这些方法。每个实体类在进行每次增删该查方法时,都会重新获取一个执行器,然后通过执行器执行sql。执行器也在AbstractEntity中创建。下面看具体代码:

 

实体类:

接口

package com.hc.core;

import java.sql.SQLException;

/**
 * 实体接口 所有数据库实体都必须实现这个接口
 * @author chuer
 * @date 2014-7-16 下午12:07:47
 * @version V1.0
 */
public interface IEntity {

	public long getId();//获得实体主键

	public void setId(long id);//设置实体主键

	public void persist() throws SQLException;//增

	public void remove() throws SQLException;//删

	public IEntity get(long id) throws SQLException;//查
	
	public void update(String columnName) throws SQLException;//改
	
	public void setExecute();//设置执行器
	
	
	public void rollBack();
	
	
	
	
}


抽象实现

package com.hc.core;

import java.sql.SQLException;

/**
 * 抽象实体类
 * @author chuer
 * @date 2014-7-16 下午12:08:42
 * @version V1.0
 */
public abstract class AbstractEntity implements IEntity {

	protected AbstractExecute<AbstractEntity> execute;
	protected EntityStatus status;

	public AbstractEntity(){
		this.status = EntityStatus.NEW;//状态为新建
	}
	
	@Override
	public void persist() throws SQLException {
		//持久化对象 只有新建的对象才可以进行持久化
		if(this.status == EntityStatus.NEW){
			setExecute();
			try{
				execute.save(this);
			}catch(SQLException e){
				rollBack();
				throw e;
			}
			this.status = EntityStatus.PERSIST;
		}
	}
	
	
	@Override
	public void remove() throws SQLException{
		//删除用户  只有持久化的对象才可以进行删除操作
		if(this.status == EntityStatus.PERSIST){
			setExecute();
			try {
				execute.delete(this);
			} catch (SQLException e) {
				rollBack();
				throw e;
			}
			this.status = EntityStatus.NEW;
		}
	}

	@Override
	public  AbstractEntity get(long id) throws SQLException {
		this.setId(id);
		this.status = EntityStatus.QUERY;
		setExecute();
		execute.get(this);
		this.status = EntityStatus.PERSIST;
		return this;
	}
	
	@Override
	public void update(String columnName) throws SQLException{
		//只有持久化对象才能进行更新操作
		if(this.status == EntityStatus.PERSIST){
			setExecute();
			try{
				execute.update(this, columnName);
			}catch(SQLException e){
				rollBack();
				throw e;
			}
		}
	}

	public EntityStatus getStatus() {
		return status;
	}

	public void setStatus(EntityStatus status) {
		this.status = status;
	}

	@Override
	public void setExecute() {
		execute = ExecuteFactory.getExecute();
	}

	@Override
	public void rollBack() {
	}
	
	
	
	
	
}

具体实现

package com.hc.sample.entity;

import java.sql.SQLException;

import com.hc.annotation.Column;
import com.hc.annotation.Entity;
import com.hc.core.AbstractEntity;
/**
 * 
 * @author chuer
 * @date 2014-7-16 上午9:33:02
 * @version V1.0
 */
@Entity(entityName="UserEntity",tableName="user_m")
public class UserEntity  extends AbstractEntity{
	
	public UserEntity(){
		super();
	}
	
	@Column(type=long.class,name="id",isPrimary=true)
	private long id;
	
	@Column(type=String.class,name="name")
	private String name;


	public long getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

	
	public void setName(String name) throws SQLException {
		this.name = name;
		//更新数据到数据库 只有持久化的数据才可以更新操作
		update("name");
	}

	
}


ID生成

生成器

package com.hc.utils;

import java.util.Date;
/**
 * id生成
 * @author chuer
 * @version 2014-7-16  上午11:38:34
 */
public class UID {
	private static Date date = new Date();
	private static StringBuilder buf = new StringBuilder();
	private static int seq = 0;
	private static final int ROTATION = 99999;

	public static synchronized long next() {
		if (seq > ROTATION)
			seq = 0;
		buf.delete(0, buf.length());
		date.setTime(System.currentTimeMillis());
		String str = String.format("%1$tY%1$tm%1$td%1$tk%1$tM%1$tS%2$05d",
				date, seq++);
		return Long.parseLong(str);
	}
	
	
	public static void main(String ...args){
		new MyThread().start();
		new MyThread().start();
		new MyThread().start();
		new MyThread().start();
		new MyThread().start();
		new MyThread().start();
		new MyThread().start();
		new MyThread().start();
		new MyThread().start();
		new MyThread().start();
	}
}

class MyThread extends Thread{

	@Override
	public void run() {
		for(int i=0;i<100;i++){
			System.out.println(UID.next());
		}
	}
}


ID池

package com.hc.pool;

import java.util.concurrent.ConcurrentLinkedQueue;

import com.hc.utils.UID;
/**
 * id池子
 * @author chuer
 * @version 2014-7-16  下午12:23:26
 */
public class IDPool {
	
	private static final int MAX_POOL_SIZE = 100000;//id池大小
	private static final int MIN_POOL_SIZE = 100;//id池大小
	private static volatile boolean isInit = false;
	private IDPool(){}
	private static IDPool pool = new IDPool();
	private ConcurrentLinkedQueue<Long> pools = new ConcurrentLinkedQueue<Long>();
	
	public static IDPool getInstance(){
		if(!isInit){
			isInit = true;
			pool.startGenerateId();
		}
		return pool;
	}
	
	public void  startGenerateId(){
		GenerateId gi = new GenerateId();
		new Thread(gi).start();
	}
	
	
	void addId(Long id){
		pools.add(id);
	}
	
	public Long applyId(){
		Long id = pools.poll();
		if(id == null){
			return UID.next();
		}
		return id;
	}
	
	class GenerateId implements Runnable{

		@Override
		public void run() {
			while(true){
				if(pools.size()<MIN_POOL_SIZE){
					while(true){
						addId(UID.next());
						if(pools.size() == MAX_POOL_SIZE){
							break;
						}
					}
				}
				
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
		}
		
	}
}


执行器

接口

package com.hc.core;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
/**
 * 增删改差接口  执行器
 * @author chuer
 * @date 2014-7-16 上午10:08:17
 * @version V1.0
 */
public interface IExecute<T> {

	public int save(T t) throws SQLException;  //保存操作

	public int update(T t, String column) throws SQLException;  //更新操作

	public int delete(T t) throws SQLException; //删除操作

	public T get(T t) throws SQLException; //单个查询操作
	
	public Collection<T> query(Class<T> cls,String sql)throws SQLException;//批量查询操作

	public void execute(String sql) throws SQLException;//执行自定义sql
	
	public void relase(Connection conn);//释放连接
	
	public void setAutoCommit(boolean autoCommit);//设置连接是否自动提交
}

 

package com.hc.core;
/**
 * 事务提交接口
 * @author chuer
 * @version 2014-7-16  上午11:27:24
 */
public interface ICommit {

	public void commit();//提交
	public void rollback();//回滚
	
}


抽象实现

package com.hc.core;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import com.hc.pool.DBConfig;
import com.hc.pool.DBPool;

/**
 * 抽象执行器
 * @author chuer
 * @date 2014-7-16 上午10:08:51
 * @version V1.0
 */
public abstract class AbstractExecute<T> implements  IExecute<T>,ICommit{

	protected Connection conn;
	protected boolean autoCommit;
	
	protected AbstractExecute(Connection conn){
		this.conn = conn;
		this.autoCommit = DBConfig.AUTOCOMMIT;
	}

	@Override
	public void commit() {
		try {
			conn.commit();
			relase(conn);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void rollback() {
		try {
			conn.rollback();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void relase(Connection conn) {
		DBPool.getInstance().relaseConnection(conn);
	}
	
	@Override
	public void execute(String sql) throws SQLException {
		System.out.println(sql);
		Statement stat = conn.createStatement();
		stat.execute(sql);
		if(autoCommit){
			commit();
		}
	}

	@Override
	public void setAutoCommit(boolean autoCommit1) {
		autoCommit = autoCommit1;
	}
	
	
	
	
	
	
}


 

具体实现

package com.hc.execute;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;

import com.hc.cache.CacheManager;
import com.hc.core.AbstractExecute;
import com.hc.core.IEntity;
import com.hc.sql.SqlManager;
import com.hc.utils.AssembleData;
import com.hc.utils.AssembleStatement;
/**
 * 执行器实现类
 * @author chuer
 * @version 2014-7-16  上午11:36:08
 * @param <T>
 */
public class ExecuteImpl<T extends IEntity> extends AbstractExecute<T>{

	public ExecuteImpl(Connection conn){
		super(conn);
	}
	
	@Override
	public int save(T t) throws SQLException {
		String insertSql = SqlManager.getInstance().getInsertSql(t.getClass());
		System.out.println(insertSql);
		PreparedStatement stat = AssembleStatement.assembleInsertSql(t, insertSql, conn);
		stat.execute();
		if(autoCommit){
			commit();
		}
		CacheManager.cache(t);
		return 0;
	}

	@Override
	public int update(T t,String column) throws SQLException {
		String updateSql = SqlManager.getInstance().getUpdateSql(t.getClass(),column);
		System.out.println(updateSql);
		PreparedStatement stat = AssembleStatement.assembleUpdateSql(t, updateSql, conn, column);
		stat.execute();
		if(autoCommit){
			commit();
		}
		return 0;
	}

	@Override
	public int delete(T t) throws SQLException {
		String deleteSql = SqlManager.getInstance().getDeleteSql(t.getClass());
		System.out.println(deleteSql);
		PreparedStatement stat = AssembleStatement.assembleDeleteSql(t, deleteSql, conn);
		stat.execute();
		if(autoCommit){
			commit();
		}
		return 0;
	}

	@Override
	public T get(T t) throws SQLException {
		String singleSql = SqlManager.getInstance().getSingleSql(t.getClass());
		System.out.println(singleSql);
		PreparedStatement stat = AssembleStatement.assembleSingleSql(t, singleSql, conn);
		ResultSet rs = stat.executeQuery();
		try {
			AssembleData.assembleSingle(t, rs);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if(autoCommit){
			commit();
		}
		return t;
	}

	@Override
	public Collection<T> query(Class<T> cls,String condition)throws SQLException {
		String querySql = SqlManager.getInstance().getQuerySql(cls);
		querySql += condition;
		System.out.println(querySql);
		Statement stat = conn.createStatement();
		ResultSet rs = stat.executeQuery(querySql);
		Collection<T> list = null;
		try {
			list = AssembleData.assembleCollection(new ArrayList<T>(), cls, rs);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if(autoCommit){
			commit();
		}
		return list;
	}


	
	

	
}


 

装配器:

package com.hc.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.hc.annotation.Column;
/**
 * sql装配
 * @author chuer
 * @version 2014-7-16  上午10:13:05
 */
public class AssembleStatement {

	
	/**
	 * 装配单个查询sql
	 * @param t
	 * @param sql
	 * @param conn
	 * @return
	 */
	public static <T> PreparedStatement assembleSingleSql(T t,String sql,Connection conn){
		try{
			PreparedStatement pStat= conn.prepareStatement(sql);
			Field[] fields = t.getClass().getDeclaredFields();
			for(Field fie : fields){
				if(fie.isAnnotationPresent(Column.class)){
					Column annotation = fie.getAnnotation(Column.class);
					if(annotation.isPrimary()){
						Object id = getColumnValue(fie.getName(), t);
						fill(annotation,pStat,1,id);
						break;
					}
				}
			}
			return pStat;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	/**
	 * 装配删除sql
	 * @param t
	 * @param sql
	 * @param conn
	 * @return
	 */
	public static <T> PreparedStatement assembleDeleteSql(T t,String sql,Connection conn){
		try{
			PreparedStatement pStat= conn.prepareStatement(sql);
			Field[] fields = t.getClass().getDeclaredFields();
			for(Field fie : fields){
				if(fie.isAnnotationPresent(Column.class)){
					Column annotation = fie.getAnnotation(Column.class);
					if(annotation.isPrimary()){
						Object id = getColumnValue(fie.getName(), t);
						fill(annotation,pStat,1,id);
						break;
					}
				}
			}
			return pStat;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	/**
	 * 装配更新sql
	 * @param t
	 * @param sql
	 * @param conn
	 * @param columnName
	 * @return
	 */
	public static <T> PreparedStatement assembleUpdateSql(T t,String sql,Connection conn,String columnName){
		try{
			PreparedStatement pStat= conn.prepareStatement(sql);
			Object value = getColumnValue(columnName, t);
			Field field = t.getClass().getDeclaredField(columnName);
			fill(field.getAnnotation(Column.class),pStat,1,value);
			
			
			Field[] fields = t.getClass().getDeclaredFields();
			for(Field fie : fields){
				if(fie.isAnnotationPresent(Column.class)){
					Column annotation = fie.getAnnotation(Column.class);
					if(annotation.isPrimary()){
						Object id = getColumnValue(fie.getName(), t);
						fill(annotation,pStat,2,id);
						break;
					}
				}
			}
			return pStat;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 装配插入sql
	 * @param t
	 * @param sql
	 * @param conn
	 * @return
	 * @throws SQLException
	 */
	public static <T> PreparedStatement assembleInsertSql(T t,String sql,Connection conn)throws SQLException{
		try{
			PreparedStatement pStat= conn.prepareStatement(sql);
			Field [] fileds = t.getClass().getDeclaredFields();
			for(int i=0;i<fileds.length;i++){
				Field field = fileds[i];
				if(field.isAnnotationPresent(Column.class)){
					Object value = getColumnValue(field.getName(),t);
					fill(field.getAnnotation(Column.class),pStat,i+1,value);
				}
			}
			return pStat;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 得到字段的值
	 * @param columnName
	 * @param t
	 * @return
	 * @throws Exception
	 */
	private static <T>  Object getColumnValue(String columnName,T t)throws Exception{
		String methodName = "get"+columnName.substring(0,1).toUpperCase()+columnName.substring(1, columnName.length());
		Method method = t.getClass().getMethod(methodName, new Class[]{});
		Object value = method.invoke(t, new Object[]{});
		return value;
	}
	/**
	 * 替换sql中的?
	 * @param ctype
	 * @param pStat
	 * @param index
	 * @param value
	 * @throws Exception
	 */
	private static void fill(Column ctype,PreparedStatement pStat,int index,Object value)throws Exception{
		Class<? extends Object> type = ctype.type();
		if(type == int.class){
			pStat.setInt(index, (int)value);
		}else if(type == byte.class){
			pStat.setByte(index, (byte)value);
		}else if(type == short.class){
			pStat.setShort(index, (short)value);
		}else if(type == long.class){
			pStat.setLong(index, (long)value);
		}else if(type == String.class){
			pStat.setString(index, (String)value);
		}
	}
}


 

package com.hc.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.util.Collection;

import com.hc.annotation.Column;
import com.hc.core.EntityStatus;

public class AssembleData {

	/**
	 * 返回集合
	 * @param list
	 * @param cls
	 * @param rs
	 * @return
	 * @throws Exception
	 */
	public static <T> Collection<T> assembleCollection(Collection<T> list,Class<T> cls,ResultSet rs)throws Exception{
		while(rs.next()){
			T instance = cls.getConstructor(new Class[]{}).newInstance(new Object[]{});
			assemble(instance,rs);
			list.add(instance);
		}
		return list;
	}
	
	private  static <T> T assemble(T t,ResultSet rs) throws Exception{
		Method method = t.getClass().getMethod("setStatus", new Class[]{EntityStatus.class});
		method.invoke(t, new Object[]{EntityStatus.QUERY});
		Field[] declaredFields = t.getClass().getDeclaredFields();
		for(Field field : declaredFields){
			if(field.isAnnotationPresent(Column.class)){
				Column annotation = field.getAnnotation(Column.class);
				
				String fieldName = field.getName();
				String ColumnName = annotation.name();
				Class<?> type = annotation.type();
				setValue(t,type,rs,ColumnName,fieldName);
			}
		}
		method.invoke(t, new Object[]{EntityStatus.PERSIST});
		return t;
	}
	/**
	 * 返回单对象
	 * @param t
	 * @param rs
	 * @return
	 * @throws Exception
	 */
	public static <T> T assembleSingle(T t,ResultSet rs) throws Exception{
		if(rs.next()){
			Field[] declaredFields = t.getClass().getDeclaredFields();
			for(Field field : declaredFields){
				if(field.isAnnotationPresent(Column.class)){
					Column annotation = field.getAnnotation(Column.class);
					
					String fieldName = field.getName();
					String ColumnName = annotation.name();
					Class<?> type = annotation.type();
					setValue(t,type,rs,ColumnName,fieldName);
				}
			}
		}
		return t;
	}
	
	private static <T,S> void setValue(T t,Class<S> type,ResultSet rs,String columnName,String fieldName)throws Exception{
		String setMethodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
		Method setMethod = t.getClass().getMethod(setMethodName, new Class[]{type});
		if(type == int.class){
			setMethod.invoke(t, new Object[]{rs.getInt(columnName)});
		}else if(type == byte.class){
			setMethod.invoke(t, new Object[]{rs.getByte(columnName)});
		}else if(type == short.class){
			setMethod.invoke(t, new Object[]{rs.getShort(columnName)});
		}else if(type == long.class){
			setMethod.invoke(t, new Object[]{rs.getLong(columnName)});
		}else if(type == String.class){
			setMethod.invoke(t, new Object[]{rs.getString(columnName)});
		}
	}
	
}


工具类Query

package com.hc.utils;

import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.Collection;

import com.hc.cache.CacheManager;
import com.hc.core.AbstractExecute;
import com.hc.core.ExecuteFactory;
import com.hc.core.IEntity;

public class Query {
	
	public static <T extends IEntity> Collection<T> query(Class<T> cls,String condition) throws SQLException{
		AbstractExecute<T> execute = ExecuteFactory.getExecute();
		return execute.query(cls, condition);
	}
	
	
	public static IEntity load(Class<?> cls,long id) throws SQLException {
		IEntity entity = CacheManager.getEntity(cls.toString()+id);
		if(entity != null){
			return entity;
		}
		IEntity newInstance = null;
		try {
			newInstance = (IEntity)cls.getConstructor(new Class[]{}).newInstance(new Object[]{});
		} catch (InstantiationException | IllegalAccessException
				| IllegalArgumentException | InvocationTargetException
				| NoSuchMethodException | SecurityException e) {
			e.printStackTrace();
		}
		newInstance.get(id);
		return newInstance;
	}
	
	public static void execute(String sql)throws SQLException{
		AbstractExecute<IEntity> execute = ExecuteFactory.getExecute();
		execute.execute(sql);
	}
	
}


测试类

package com.hc.execute;

import com.hc.pool.IDPool;
import com.hc.sample.entity.UserEntity;

public class TestExecute {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		
		UserEntity user  = new UserEntity();
		Long applyId = IDPool.getInstance().applyId();
		user.setId(applyId);
		
		
		user.setName("chujiinhui");
		
		//持久化用户
		user.persist();
		
		
		//查询此用户
		user = (UserEntity)user.get(applyId);
		System.out.println(user.getName());
		
		
		//更新此用户
		user.setName("hello");
		
		
		user = (UserEntity)user.get(applyId);
		System.out.println(user.getName());
		
		
	}

}


 

运行结果如下:

 

insert into user_m(id,name) values (?,?)
select * from user_m where 1=1 and id=?
chujiinhui
update user_m set name=? where id=?
select * from user_m where 1=1 and id=?
hello


查看数据库也存在已添加的数据。

 



 

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值