首页 > 技术文章 > MongoDB与Spring整合(支持事务)——SpringDataMongoDB

vettel0329 2019-04-25 14:25 原文

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);
    }

 

推荐阅读