目录导航
前言
前面的章节,关于分布式缓存技术,我们分析了《分布式缓存技术之Redis的使用以及原理》、从这一节开始,继续来说说MongoDB。
关于MongoDB,一共五小节内容,分别是:
Java操作MongoDB的API介绍
首先要导入pom依赖:
<!-- mongo官方推荐的一个ORM框架 -->
<dependency>
<groupId>org.mongodb.morphia</groupId>
<artifactId>morphia</artifactId>
<version>1.3.2</version>
</dependency>
NativeCRUD
使用原生的mongoClient向test-demo数据库插入Document 类型的一条数据:
public static void main(String[] args) {
MongoClient mongoClient = MongoClients.create("mongodb://192.168.200.111:27017");
MongoDatabase db = mongoClient.getDatabase("test-demo");
MongoCollection coll = db.getCollection("t_member");
Document doc = new Document("name", "MongoDB")
.append("type", "database")
.append("count", 1)
.append("versions", Arrays.asList("v3.2", "v3.0", "v2.6"))
.append("info", new Document("x", 203).append("y", 102));
coll.insertOne(doc);
// System.out.println(mongoClient);
}
效果展示:
成功插入
MongoCRUD
使用DBCollection 向test-demo数据库插入DBObject 类型的一条数据:
public static void main(String[] args) {
Mongo mongo = new Mongo("192.168.200.111",27017);
DB db = new DB(mongo,"test-demo");
DBCollection collection = db.getCollection("member");
//类比法:JDBC,相对来说比较底层
DBObject dbObject = new BasicDBObject();
dbObject.put("name","Tom");
dbObject.put("age",18);
dbObject.put("addr","HunanChangsha");
collection.insert(dbObject);
DBCursor cursor = collection.find();
for (DBObject obj : cursor){
System.out.println(obj);
}
}
效果展示:
插入成功
Morphia
使用Morphia向test-demo数据库插入Member 类型的一条数据:
public static void main(String[] args) {
//吗啡
final Morphia morphia = new Morphia();
Datastore ds = morphia.createDatastore(new MongoClient("192.168.200.111",27017),"test-demo");
Member member = new Member();
member.setName("Tom");
member.setAge(18);
member.setAddr("HunanChangsha");
Key<Member> key = ds.save(member);
System.out.println(key.getId());
}
Member
public class Member {
@Id
private ObjectId id;
private String name;
private int age;
private String addr;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
效果展示:
插入成功
手写实现基于MongoDB的ORM框架
手写ORM的意义
1、结合业务场景,需要手写,解放 双手。
2、主要讲实现思想及原理。
3、更好地监控、统一管理和维护(可控性更强)。
手写基于MongoDB的ORM框架
我们在前面的章节讲到了基于手写jdbc的orm框架,那个是为了mysql数据库准备的,这里我们基于MongoDB数据库来手写orm框架,功能上类似于mybatis-plus(在mybatis的基础上进一步封装,让使用者面向对象操作mysql数据库~)。
本节只截取部分核心代码,全部代码请移步至文末后记部分,有gitlhub分享地址,欢迎访问~
完整代码目录结构:
流程梳理
因为我用的是springboot项目,所以直接在项目引入mongodb:
关于工具类:
- BeanUtils:扩展Apache Commons BeanUtils, 提供一些反射方面缺失功能的封装.
- DataUtils:提供各种对数据进行处理的方法
- GenericsUtils:泛型操作类
- ObjectUtils:对象工具类
- StringUtils:String工具类
关于核心类BaseDaoSupport,实际上是对于mongoTemplate进一步封装
public abstract class BaseDaoSupport<T extends Serializable,PK extends Serializable> {
private MongoTemplate mongoTemplate;
private EntityOperation<T> op;
public BaseDaoSupport(){
Class<T> entityClass = GenericsUtils.getSuperClassGenricType(getClass(),0);
op = new EntityOperation<T>(entityClass);
}
protected void setTempate(MongoTemplate tempate){
this.mongoTemplate = tempate;
}
protected abstract String getPKColumn();
//可控
protected List<T> find(QueryRule queryRule){
// "starttime " + "" + System.currentTimeMillis();
QueryRuleBulider bulider = new QueryRuleBulider(queryRule);
Query query = bulider.getQuery();
return mongoTemplate.find(query,op.entityClass);
}
protected int saveAll(List<T> list){
mongoTemplate.insertAll(list);
return list.size();
}
protected T get(PK id){
QueryRule queryRule = QueryRule.getInstance();
queryRule.andEqual(this.getPKColumn(),id);
QueryRuleBulider bulider = new QueryRuleBulider(queryRule);
Query query = bulider.getQuery();
return mongoTemplate.findOne(query,op.entityClass);
}
protected int delete(T entity){
return mongoTemplate.remove(entity).getN();
}
}
CustomConfig 加载自定义配置:
public class CustomConfig extends PropertyPlaceholderConfigurer{
private final String PLACEHOLDER_START = "${";
private static Map<String, String> ctx;
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,Properties props) throws BeansException {
resolvePlaceHolders(props);
super.processProperties(beanFactoryToProcess, props);
ctx = new HashMap<String, String>();
for (Object key : props.keySet()) {
String keyStr = key.toString();
String value = props.getProperty(keyStr);
ctx.put(keyStr, value);
}
}
/**
* 获取已加载的配置信息
* @param key
* @return
*/
public static String getValue(String key) {
return ctx.get(key);
}
/**
* 获取已加载的配置信息
* @param key
* @return
*/
public static String getString(String key) {
return ctx.get(key);
}
/**
* 获取已加载的配置信息
* @param key
* @return
*/
public static int getInt(String key) {
return Integer.valueOf(ctx.get(key));
}
/**
* 获取已加载的配置信息
* @param key
* @return
*/
public static boolean getBoolean(String key) {
return Boolean.valueOf(ctx.get(key));
}
/**
* 获取已加载的配置信息
* @param key
* @return
*/
public static long getLong(String key) {
return Long.valueOf(ctx.get(key));
}
/**
* 获取已加载的配置信息
* @param key
* @return
*/
public static short getShort(String key) {
return Short.valueOf(ctx.get(key));
}
/**
* 获取已加载的配置信息
* @param key
* @return
*/
public static float getFloat(String key) {
return Float.valueOf(ctx.get(key));
}
/**
* 获取已加载的配置信息
* @param key
* @return
*/
public static double getDouble(String key) {
return Double.valueOf(ctx.get(key));
}
/**
* 获取所有的key值
* @return
*/
public static Set<String> getKeys(){
return ctx.keySet();
}
/**
* 解析占位符
* @param properties
*/
private void resolvePlaceHolders(Properties properties) {
Iterator itr = properties.entrySet().iterator();
while ( itr.hasNext() ) {
final Map.Entry entry = ( Map.Entry ) itr.next();
final Object value = entry.getValue();
if ( value != null && String.class.isInstance( value ) ) {
final String resolved = resolvePlaceHolder(properties, (String)value );
if ( !value.equals( resolved ) ) {
if ( resolved == null ) {
itr.remove();
}
else {
entry.setValue( resolved );
}
}
}
}
}
/**
* 解析占位符具体操作
* @param prots
* @param value
* @return
*/
private String resolvePlaceHolder(Properties prots,String value) {
if ( value.indexOf( PLACEHOLDER_START ) < 0 ) {
return value;
}
StringBuffer buff = new StringBuffer();
char[] chars = value.toCharArray();
for ( int pos = 0; pos < chars.length; pos++ ) {
if ( chars[pos] == '$' ) {
if ( chars[pos+1] == '{' ) {
String key = "";
int x = pos + 2;
for ( ; x < chars.length && chars[x] != '}'; x++ ) {
key += chars[x];
if ( x == chars.length - 1 ) {
throw new IllegalArgumentException( "unmatched placeholder start [" + value + "]" );
}
}
String val = extractFromSystem(prots, key);
buff.append( val == null ? "" : val );
pos = x + 1;
if ( pos >= chars.length ) {
break;
}
}
}
buff.append( chars[pos] );
}
String rtn = buff.toString();
return isEmpty( rtn ) ? null : rtn;
}
/**
* 获得系统属性 当然 你可以选择从别的地方获取值
* @param prots
* @param key
* @return
*/
private String extractFromSystem(Properties prots,String key) {
try {
return prots.getProperty(key);
}
catch( Throwable t ) {
return null;
}
}
/**
* 判断字符串的空(null或者.length=0)
* @param string
* @return
*/
private boolean isEmpty(String string) {
return string == null || string.length() == 0;
}
}
核心类:QueryRule 可以参考mybatis-plus
public final class QueryRule implements Serializable {
private static final long serialVersionUID = 1L;
public static final int ASC_ORDER = 101;
public static final int DESC_ORDER = 102;
private List<Rule> ruleList = new ArrayList<Rule>();
private List<QueryRule> queryRuleList = new ArrayList<QueryRule>();
private String propertyName;
private QueryRule() {}
private QueryRule(String propertyName) {
this.propertyName = propertyName;
}
public static QueryRule getInstance() {
return new QueryRule();
}
/**
* 添加升序规则
* @param propertyName
* @return
*/
public QueryRule addAscOrder(String propertyName) {
this.ruleList.add(new Rule(ASC_ORDER, propertyName));
return this;
}
/**
* 添加降序规则
* @param propertyName
* @return
*/
public QueryRule addDescOrder(String propertyName) {
this.ruleList.add(new Rule(DESC_ORDER, propertyName));
return this;
}
//更多规则,这里不做截图,完整代码直接看github地址即可
}
ORM代码测试
我们以insertAll和selectAll做一个简单的测试:
@Test
public void testInsertAll(){
List<Member> data = new ArrayList<Member>();
data.add(new Member("tom","123456",1,18));
memberDao.insertAll(data);
}
@Test
public void testSelect(){
QueryRule queryRule = QueryRule.getInstance();
queryRule.andEqual("nickname","tom");
List<Member> memberList = memberDao.select(queryRule);
System.out.println(JSON.toJSONString(memberList,true));
}
测试结果:
插入成功~
看看查询结果:
查询成功~
ORM的CRUD其他方法,读者有兴趣可自行从github下载使用
后记
java操作mongodb的api代码:
https://github.com/harrypottry/mongo-morphia
手写基于mongodb的ORM框架代码:
https://github.com/harrypottry/mongo-orm
更多架构知识,欢迎关注本套Java系列文章:
Java架构师成长之路