MongoDB与Spring整合(支持事务)——SpringDataMongoDB
1.将MongoDB设置为复制集模式
a.修改 mongod.cfg 文件,添加replSetName复制集名称
#replication: replication: replSetName: "rs0"
b.在MongDB命令行输入初始化添加 localhost:27017 节点
rs.initiate( {_id : "rs0",members: [ { _id: 0, host: "localhost:27017" } ]})
2.添加maven依赖
<!-- mongo --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>2.1.1.RELEASE</version> </dependency>
注:a.支持事务MongoDB要4.0版本以上,使用复制集,单节点不支持。
b.Spring要 5.1.1.RELEASE 以上
c.SpringDataMongoDB要 2.1.1.RELEASE 以上
d.使用事务之前(@Transaction),数据库、文档、索引必须提前创建
3.书写 spring-mongo.xml 及对应 mongo.properties
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:property-placeholder location="classpath:mongo.properties"/> <!-- <mongo:mongo-client id="mongo-client" host="${mongo.host}" port="${mongo.port}"> --> <mongo:mongo-client id="mongo-client" replica-set="${mongo.replSet}"> <mongo:client-options connections-per-host="${mongo.connectionsPerHost}" threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}" connect-timeout="${mongo.connectTimeout}" max-wait-time="${mongo.maxWaitTime}" socket-keep-alive="${mongo.socketKeepAlive}" socket-timeout="${mongo.socketTimeout}" /> </mongo:mongo-client> <mongo:repositories base-package="com.wode.dao"/> <mongo:db-factory dbname="${mongo.db}" mongo-ref="mongo-client"/> <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> </bean> <bean id="mongoTransactionManager" class="org.springframework.data.mongodb.MongoTransactionManager"> <constructor-arg name="dbFactory" ref="mongoDbFactory"/> </bean> <tx:annotation-driven transaction-manager="mongoTransactionManager" proxy-target-class="true"/> </beans>
mongo.host=localhost mongo.port=27017 mongo.replSet=localhost:27017 mongo.db=testmongo #################连接池配置################# #最大连接数 mongo.connectionsPerHost=8 #可被阻塞的线程数因子,默认值为5,如果connectionsPerHost配置为10,那么最多能阻塞50个线程,超过50个之后就会收到一个异常 mongo.threadsAllowedToBlockForConnectionMultiplier=4 #连接超时时间,默认值是0,就是不超时 mongo.connectTimeout=1000 #阻塞线程获取连接的最长等待时间,默认120000 ms mongo.maxWaitTime=1500 #keep alive标志,默认false mongo.socketKeepAlive=true #socket超时时间,默认值是0,就是不超时 mongo.socketTimeout=1500
4.创建实体类
public class BaseBean { @Id private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } }
@Document public class Cmdty extends BaseBean { private String cmdtyCode; private String cmdtyName; private List<Attr> attributes; @DBRef private Info info; public String getCmdtyCode() { return cmdtyCode; } public void setCmdtyCode(String cmdtyCode) { this.cmdtyCode = cmdtyCode; } public String getCmdtyName() { return cmdtyName; } public void setCmdtyName(String cmdtyName) { this.cmdtyName = cmdtyName; } public List<Attr> getAttributes() { return attributes; } public void setAttributes(List<Attr> attributes) { this.attributes = attributes; } public Info getInfo() { return info; } public void setInfo(Info info) { this.info = info; } @Override public String toString() { return "[Cmdty]: cmdtyCode[" + cmdtyCode + "], cmdtyName[" + cmdtyName + "], attributes[" + attributes + "], info[" + info + "]"; } }
public class Attr extends BaseBean { private String key; private String value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } @Override public String toString() { return "[Attr]: key[" + key + "], value[" + value + "]"; } }
@Document public class Info extends BaseBean { private String color; private String style; public String getColor() { return color; } public void setColor(String color) { this.color = color; } public String getStyle() { return style; } public void setStyle(String style) { this.style = style; } @Override public String toString() { return "[Info]: color[" + color + "], style[" + style + "]"; } }
5.通过 MongoTemplate 的方式
a.创建Dao
@Repository public class TestDao { @Resource protected MongoTemplate mongoTemplate; private Class<Cmdty> clazz; @PostConstruct private void construct(){ clazz = Cmdty.class; } //添加 public Cmdty insert(Cmdty t) { return mongoTemplate.insert(t); } //保存 public Cmdty save(Cmdty t) { return mongoTemplate.save(t); } //保存商品信息 public Info saveInfo(Info t) { return mongoTemplate.save(t); } //修改 public int update(Map<String, Object> filter, Map<String, Object> updater) { UpdateResult result = mongoTemplate.updateMulti(this.getQuery(filter), this.getUpdater(updater), this.clazz); return (int) result.getModifiedCount(); } //删除 public long delete(Map<String, Object> filter) { DeleteResult result = mongoTemplate.remove(this.getQuery(filter), this.clazz); return result.getDeletedCount(); } //存在 public boolean exist(Map<String, Object> filter) { return mongoTemplate.exists(this.getQuery(filter), this.clazz); } //个数 public long count(Map<String, Object> filter) { return mongoTemplate.count(this.getQuery(filter), this.clazz); } //查询一个 public Cmdty getObject(Map<String, Object> filter) { return mongoTemplate.findOne(this.getQuery(filter), this.clazz); } //查询多个 public List<Cmdty> getList(Map<String, Object> filter) { return mongoTemplate.find(this.getQuery(filter), this.clazz); } protected Query getQuery(Map<String, Object> filter){ Query query = new Query(); for(Map.Entry<String, Object> entry : filter.entrySet()){ String key = entry.getKey(); Object value = entry.getValue(); switch (key){ case "id": query = query.addCriteria(Criteria.where("_id").is(value)); break; case "cmdtyName": query = query.addCriteria(Criteria.where("cmdtyName").is(value)); break; case "cmdtyNameLike": Pattern pattern = Pattern.compile("^.*"+value+".*$", Pattern.CASE_INSENSITIVE); query = query.addCriteria(Criteria.where("cmdtyName").regex(pattern)); break; case "cmdtyCode": query = query.addCriteria(Criteria.where("cmdtyCode").is(value)); break; default: break; } } return query; } protected Update getUpdater(Map<String, Object> updater) { Update update = new Update(); for(Map.Entry<String, Object> entry : updater.entrySet()){ update.set(entry.getKey(), entry.getValue()); } return update; } }
b.创建Service
@Service public class TestService { @Resource private TestDao dao; @Transactional public boolean saveCmdty(Cmdty cmdty, Info info){ dao.saveInfo(info); // int a = 1/0; //回滚测试代码 dao.save(cmdty); return true; } }
c.测试代码
public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); TestService service = (TestService) applicationContext.getBean("testService"); //商品信息 Info info = new Info(); info.setColor("silver"); info.setStyle("111"); //商品 Cmdty cmdty = new Cmdty(); cmdty.setCmdtyCode("Ag111"); cmdty.setCmdtyName("银111"); //商品属性 List<Attr> attributes = new ArrayList<>(); Attr attribute = new Attr(); attribute.setKey("品质"); attribute.setValue("特优"); attributes.add(attribute); cmdty.setInfo(info); cmdty.setAttributes(attributes); service.saveCmdty(cmdty, info); }
d.其他
①.排序:
Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC; query.with(new Sort(direction, sort));
②.分页:
int skip = (pageIndex - 1) * pageSize; query.skip(skip).limit(pageSize);
或者
Pageable pageable = new PageRequest(pageIndex, pageSize); query.with(pageable);
③.返回指定字段:
Document document = new Document(); for(String field : fields){ document.put(field, isReturn); } Query query = new BasicQuery(new Document(), document);
6.使用 MongoRepository 的方式
a.书写Dao接口,继承 MongoRepository
@Repository public interface TestRepositoryDao extends MongoRepository<Cmdty, String> { @Query(value="{'info.$id': ?0 }") public Cmdty findByInfoId(ObjectId id); public Cmdty findByCmdtyCode(String cmdtyCode); }
注:这种方式也支持 JPA 命名规则
b.书写Service
@Service public class TestRepositoryService { @Resource private TestRepositoryDao dao; public Cmdty findByInfoId(String infoId){ return dao.findByInfoId(new ObjectId(infoId)); } public Cmdty findByCmdtyCode(String cmdtyCode){ return dao.findByCmdtyCode(cmdtyCode); } }
e.测试
public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); TestRepositoryService service = (TestRepositoryService) applicationContext.getBean("testRepositoryService"); // Cmdty cmdty = service.findByInfoId("5cc15f32a0e5eaeb0413dfde"); Cmdty cmdty = service.findByCmdtyCode("Ag111"); System.out.println(cmdty); }