Mapper类
package cn.lsh.kafka.db.dao;
import cn.lsh.kafka.db.entity.OffsetEntity;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* kafka偏移量(Offset)表数据库访问层
*
* @author makejava
* @since 2020-12-08 14:33:12
*/
public interface OffsetMapper {
/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
@Select("SELECT * from offset where id = #{id}")
OffsetEntity queryById(Integer id);
@Select("SELECT * from offset where group_id = #{groupId} and topic = #{topic} and partition_id = #{partitionId}")
OffsetEntity queryByCond(@Param("groupId") String groupId, @Param("topic") String topic, @Param("partitionId") int partitionId);
/**
* 查询指定行数据
*
* @param offset 查询起始位置
* @param limit 查询条数
* @return 对象列表
*/
@Select("SELECT * from offset limit #{limit} offset #{offset}")
List<OffsetEntity> queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit);
/**
* 通过实体作为筛选条件查询
*
* @param offset 实例对象
* @return 对象列表
*/
List<OffsetEntity> queryAll(OffsetEntity offset);
/**
* 新增数据
*
* @param offset 实例对象
* @return 影响行数
*/
@Insert("INSERT INTO offset(group_id,topic,partition_id,value,create_date,update_date) VALUES(#{groupId},#{topic},#{partitionId},#{value},#{createDate},#{updateDate})")
int insert(OffsetEntity offset);
/**
* 修改数据
*
* @param offset 实例对象
* @return 影响行数
*/
@Update("UPDATE offset SET value = #{value}, update_date=#{updateDate} where id = #{id}")
int update(OffsetEntity offset);
/**
* 通过主键删除数据
*
* @param id 主键
* @return 影响行数
*/
@Delete("DELETE FROM offset where id = #{id}")
int deleteById(Integer id);
}
mybatis的Mapper类支持注解的方式映射sql语句,省去了mapper的xml映射文件。
基类Service
package cn.lsh.kafka.db.service;
import org.apache.ibatis.session.SqlSession;
public abstract class BaseService<T> {
protected SqlSession sqlSession;
/** 泛型T为实体的Mapper类 */
protected T mapper;
public BaseService(SqlSession sqlSession) {
//为service装载sqlSession
this.sqlSession = sqlSession;
}
protected void commit() {
this.sqlSession.commit();
}
protected void close() {
//private不能被子类继承,protect可以被子类继承,但是不能被反射出来
this.close();
}
public void setMapper(Class<T> t) {
try {
this.mapper = this.sqlSession.getMapper(t);
} catch (Exception e) {
this.sqlSession.getConfiguration().addMapper(t);
this.mapper = sqlSession.getMapper(t);
}
}
}
所有Service都继承这个抽象类,这个类主要关注以下三个地方:
- 泛型:泛型必须申明为实体对应Mapper映射类;
- sqlSession:该类维持一个sqlSession,通过构造器加载,供其继承类使用;
- setMapper:实现了一个setMapper方法,该方法自动为service注册Mapper到sqlSession。
业务Service接口
public interface OffsetService {
/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
OffsetEntity queryById(Integer id);
OffsetEntity queryByCond(String groupId, String topic, int partitionId);
/**
* 查询多条数据
*
* @param offset 查询起始位置
* @param limit 查询条数
* @return 对象列表
*/
List<OffsetEntity> queryAllByLimit(int offset, int limit);
/**
* 新增数据
*
* @param offset 实例对象
* @return 实例对象
*/
OffsetEntity insert(OffsetEntity offset);
/**
* 修改数据
*
* @param offset 实例对象
* @return 实例对象
*/
OffsetEntity update(OffsetEntity offset);
void update(int id, long value);
/**
* 通过主键删除数据
*
* @param id 主键
* @return 是否成功
*/
boolean deleteById(Integer id);
}
定义业务处理接口方法,没有其他特殊逻辑。
业务接口实现类
public class OffsetServiceImpl extends BaseService<OffsetMapper> implements OffsetService {
// private OffsetMapper offsetMapper;
public OffsetServiceImpl(SqlSession sqlSession) {
super(sqlSession);
}
/*public OffsetServiceImpl() {
TransactionFactory factory = new JdbcTransactionFactory();
DataSource dataSource = new PooledDataSource("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/bigdata", "root", "admin");
Environment environment = new Environment("ID", factory, dataSource);
Configuration conf = new Configuration(environment);
conf.addMapper(OffsetMapper.class);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(conf);
this.sqlSession = sessionFactory.openSession();
offsetMapper = sqlSession.getMapper(OffsetMapper.class);
}*/
/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
@Override
public OffsetEntity queryById(Integer id) {
return this.mapper.queryById(id);
}
@Override
public OffsetEntity queryByCond(String groupId, String topic, int partitionId) {
return this.mapper.queryByCond(groupId, topic, partitionId);
}
/**
* 查询多条数据
*
* @param offset 查询起始位置
* @param limit 查询条数
* @return 对象列表
*/
@Override
public List<OffsetEntity> queryAllByLimit(int offset, int limit) {
return this.mapper.queryAllByLimit(offset, limit);
}
/**
* 新增数据
*
* @param offset 实例对象
* @return 实例对象
*/
@Override
public OffsetEntity insert(OffsetEntity offset) {
this.mapper.insert(offset);
return offset;
}
/**
* 修改数据
*
* @param offset 实例对象
* @return 实例对象
*/
@Override
public OffsetEntity update(OffsetEntity offset) {
this.mapper.update(offset);
return this.queryById(offset.getId());
}
@Override
public void update(int id, long value) {
OffsetEntity offset = new OffsetEntity();
offset.setId(id);
offset.setValue(value);
offset.setUpdateDate(new Date());
this.mapper.update(offset);
}
/**
* 通过主键删除数据
*
* @param id 主键
* @return 是否成功
*/
@Override
public boolean deleteById(Integer id) {
boolean flag = this.mapper.deleteById(id) > 0;
return flag;
}
public static void main(String[] args) {
// OffsetService service = new OffsetServiceImpl();
OffsetService service = ServiceFactory.buildService(OffsetService.class);
OffsetEntity entity = new OffsetEntity();
entity.setGroupId("11111");
entity.setPartitionId(1);
entity.setTopic("adad");
entity.setValue(10L);
Date now = new Date();
entity.setCreateDate(now);
entity.setUpdateDate(now);
service.insert(entity);
OffsetEntity offsetEntity = service.queryById(5);
System.out.println(offsetEntity);
ServiceFactory.commitAndClose();
}
}
需要继承BaseService,并继承其构造器实现。其他就都是业务接口实现了。
Service工厂类
public class ServiceFactory {
private static SqlSession sqlSession;
//私有构造器
private ServiceFactory() {}
public static SqlSession createSession() {
//维持一个单例sqlSession
if (sqlSession == null) {
TransactionFactory factory = new JdbcTransactionFactory();
DataSource dataSource = new PooledDataSource("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/bigdata", "root", "admin");
Environment environment = new Environment("ID", factory, dataSource);
Configuration conf = new Configuration(environment);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(conf);
sqlSession = sessionFactory.openSession();
}
return sqlSession;
}
public static void commit() {
if (sqlSession != null) {
sqlSession.commit();
}
}
public static void close() {
if (sqlSession != null) {
sqlSession.close();
}
}
public static void commitAndClose() {
commit();
close();
}
public static <T> T buildService(Class<T> clazz) {
try {
String name = clazz.getName();
String implName = name.replaceAll(clazz.getSimpleName(), "impl.") + clazz.getSimpleName() + "Impl";
//反射加载service的实现类
Class<?> implClass = clazz.getClassLoader().loadClass(implName);
Constructor<?> constructor = implClass.getConstructor(SqlSession.class);
Object o = constructor.newInstance(createSession());
String mapperName = name.replaceAll(clazz.getSimpleName(), clazz.getSimpleName().replaceAll("Service", "Mapper")).replaceAll("service", "dao");
//反射加载Mapper类
Class<?> mapperClass = clazz.getClassLoader().loadClass(mapperName);
//反射调用BaseService的setMapper向SQLSession中注册Mapper
Method setMapper = implClass.getMethod("setMapper", Class.class);
setMapper.invoke(o, mapperClass);
return (T) o;
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException | ClassNotFoundException e) {
throw new RuntimeException("反射Service异常--" + e);
}
}
}
通过ServiceFactory反射Service实现类实例。该工厂类采用单例模式,私有化构造器,维护一个SQLSession。主要有两个方法:
- createSession:这个方法连接数据库,构建sqlSession会话对象;
- buildService:这个方法通过反射构建Service实现类,主要有以下几步
1、接收一个Service的class对象
2、通过class拼装器实现类的全路径名
3、反射获得service的实现类对象,同时会为其装载SQLSession
4、反射加载Mapper类
5、反射调用BaseService的setMapper向SQLSession中注册
Mapper
6、返回加载好的Service实现类对象
存在问题
service实现类需要继承BaseService,导致无法继承其他类,还需后续研究改进。