Spring Data MongoDB 二:新增、刪除操作
一.簡介
Spring Data MongoDB 專案提供與MongoDB文件資料庫的整合,Spring與Hibernate整合時,Spring提供了org.springframework.orm.hibernate3.HibernateTemplate實現了對資料的CRUD操作, Spring Data MongoDB提供了org.springframework.data.mongodb.core.MongoTemplate對MongoDB的CRUD的操作,包括對整合的物件對映檔案和POJO之間的CRUD的操作。
今天我們要介紹Java程式碼實現對MongoDB實現新增和刪除操作。
二.新增
Spring Data MongoDB 的MongoTemplate提供了兩種儲存文件方式,分別是save和insert方法,這兩種的區別:
(1)save :我們在新增文件時,如果有一個相同_ID的文件時,會覆蓋原來的。
(2)insert:我們在新增文件時,如果有一個相同的_ID時,就會新增失敗。
1.接下來我們分別介紹的兩種方式的具體語法。
(1)Save方式
方法:
1)void save (Object objectToSave) 儲存文件到預設的集合。
2)void save(Object objectToSave, String collectionName) 對指定的集合進行儲存。
(2) Insert方式
方法:
1)void insert(Object objectToSave) 儲存文件到預設的集合。
2)void insertAll(Object objectsToSave) 批量新增到預設的集合。
3)void insert(Object objectToSave, String collectionName) 對指定的集合進行儲存。
2. Spring實現MongoDB的新增操作
(1)介紹介面以及實現方法
第一步:實現一個基礎介面,是比較通用的 MongoBase.java類
public interface MongoBase<T> { // insert新增 public void insert(T object,String collectionName); // save新增 public void save(T object,String collectionName); //批量新增 public void insertAll(List<T> object); }
第二步:我們實現文件的結構,也是實體類。
我們這邊有兩個實體類,訂單類(Orders.java)和對應訂單詳情類(Item.java),這裡我們實現內嵌文件。如果沒有內嵌文件的結構,只要對一個實體類的操作就OK。
1)Orders.Java
/**
* 訂單
* @author zhengcy
*
*/
public class Orders implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
//ID
private String id;
//訂單號
private String onumber;
//日期
private Date date;
//客戶名稱
private String cname;
//訂單
private List<Item> items;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getOnumber() {
return onumber;
}
public void setOnumber(String onumber) {
this.onumber = onumber;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
2) Item.java
/**
* 產品訂購表
* @author zhengcy
*
*/
public class Item {
//數量
private Integer quantity;
//單價
private Double price;
//產品編碼
private String pnumber;
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getPnumber() {
return pnumber;
}
public void setPnumber(String pnumber) {
this.pnumber = pnumber;
}
}
第三步:實現OrdersDao類,就是實現Orders自己操作資料庫的介面,這個OrdersDao也繼承了MongoBase介面,我們這邊OrdersDao沒實現其他額外的介面。
/**
* 訂單Dao
* @author zhengcy
*
*/
public interface OrdersDao extends MongoBase<Orders> {
}
第四步:實現OrdersDaoImpl具體類,這邊是實際操作資料庫。
/**
* 訂單實現
* @author zhengcy
*
*/
@Repository("ordersDao")
public class OrdersDaoImpl implements OrdersDao {
@Resource
private MongoTemplate mongoTemplate;
@Override
public void insert(Orders object, String collectionName) {
mongoTemplate.insert(object, collectionName);
}
@Override
public void save(Orders object, String collectionName) {
mongoTemplate.save(object, collectionName);
}
@Override
public void insertAll(List<Orders> objects) {
mongoTemplate.insertAll(objects);
}
}
(2)實現測試類,我們進行測試
我們這邊為了節省時間,就沒寫服務類,我們直接呼叫dao就可以了,實現了TestOrders.java類
/**
* 測試訂單
* @author zhengcy
*
*/
public class TestOrders {
private static OrdersDao ordersDao;
private static ClassPathXmlApplicationContext app;
private static String collectionName;
@BeforeClass
public static void initSpring() {
try {
app = new ClassPathXmlApplicationContext(new String[] { "classpath:applicationContext-mongo.xml",
"classpath:spring-dispatcher.xml" });
ordersDao = (OrdersDao) app.getBean("ordersDao");
collectionName ="orders";
} catch (Exception e) {
e.printStackTrace();
}
}
//測試Save方法新增
@Test
public void testSave() throws ParseException
{
}
//測試Insert方法新增
@Test
public void testInsert() throws ParseException
{
}
//測試InsertAll方法新增
@Test
public void testInsertAll() throws ParseException
{
}
}
1)測試Save方法新增
//測試Save方法新增
@Test
public void testSave() throws ParseException
{
SimpleDateFormat form=new SimpleDateFormat("yyyy-mm-dd");
//訂單
Orders order =new Orders();
order.setOnumber("001");
order.setDate(form.parse("2015-07-25"));
order.setCname("zcy");
//訂單詳情
List<Item> items=new ArrayList<Item>();
Item item1=new Item();
item1.setPnumber("p001");
item1.setPrice(4.0);
item1.setQuantity(5);
items.add(item1);
Item item2=new Item();
item2.setPnumber("p002");
item2.setPrice(8.0);
item2.setQuantity(6);
items.add(item2);
order.setItems(items);
ordersDao.insert(order,collectionName);
}
我們到MongoDB查詢時,訂單內嵌訂單詳情的文件,說明我們成功新增文件。
測試Insert方法新增,這邊就不在詳情的介紹,跟Save方法一樣。
2)測試InsertALL方法新增
//測試InsertAll方法新增
@Test
public void testInsertAll() throws ParseException
{
List<Orders> orders=new ArrayList<Orders>();
for(int i=1;i<=10;i++){
SimpleDateFormat form=new SimpleDateFormat("yyyy-mm-dd");
//訂單
Orders order =new Orders();
order.setOnumber("00"+i);
order.setDate(form.parse("2015-07-25"));
order.setCname("zcy"+i);
//訂單詳情
List<Item> items=new ArrayList<Item>();
Item item1=new Item();
item1.setPnumber("p00"+i);
item1.setPrice(4.0+i);
item1.setQuantity(5+i);
items.add(item1);
Item item2=new Item();
item2.setPnumber("p00"+(i+1));
item2.setPrice(8.0+i);
item2.setQuantity(6+i);
items.add(item2);
order.setItems(items);
orders.add(order);
}
ordersDao.insertAll(orders);
}<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
我們批量新增10條訂單內嵌訂單詳情的文件,我們在MongoDB查詢時,有查到資料,說明我們插入成功。
> db.orders.find()
{ "_id" : ObjectId("55b387ebee10f907f1c9d461"), "_class" : "com.mongo.model.Orders", "onumber" : "001", "date" : ISODate("2015-01-24T16:07:00Z"), "cname" : "zcy1", "items" : [ { "quantity" : 6, "price" : 5, "pnumber" : "p001" }, { "quantity" : 7, "price" : 9, "pnumber" : "p002" } ] }
{ "_id" : ObjectId("55b387ebee10f907f1c9d462"), "_class" : "com.mongo.model.Orders", "onumber" : "002", "date" : ISODate("2015-01-24T16:07:00Z"), "cname" : "zcy2", "items" : [ { "quantity" : 7, "price" : 6, "pnumber" : "p002" }, { "quantity" : 8, "price" : 10, "pnumber" : "p003" } ] }
{ "_id" : ObjectId("55b387ebee10f907f1c9d463"), "_class" : "com.mongo.model.Orders", "onumber" : "003", "date" : ISODate("2015-01-24T16:07:00Z"), "cname" : "zcy3", "items" : [ { "quantity" : 8, "price" : 7, "pnumber" : "p003" }, { "quantity" : 9, "price" : 11, "pnumber" : "p004" } ] }
{ "_id" : ObjectId("55b387ebee10f907f1c9d464"), "_class" : "com.mongo.model.Orders", "onumber" : "004", "date" : ISODate("2015-01-24T16:07:00Z"), "cname" : "zcy4", "items" : [ { "quantity" : 9, "price" : 8, "pnumber" : "p004" }, { "quantity" : 10, "price" : 12, "pnumber" : "p005" } ] }
{ "_id" : ObjectId("55b387ebee10f907f1c9d465"), "_class" : "com.mongo.model.Orders", "onumber" : "005", "date" : ISODate("2015-01-24T16:07:00Z"), "cname" : "zcy5", "items" : [ { "quantity" : 10, "price" : 9, "pnumber" : "p005" }, { "quantity" : 11, "price" : 13, "pnumber" : "p006" } ] }
...........
>
3)如果面對相同的_ID時,我們在使用Save和Insert時,會碰到我們前面介紹的那樣?我們測試一下就知道了。
我們在新增文件時,如果不設定_ID屬性值,文件新增到MongoDB時,對於objectID的ID屬性/欄位自動生成一個字串,帶有索引和唯一性。如果我們指定_ID屬性值時,速度會很慢,因為_ID預設是有索引的。
> db.orders.find()
{ "_id" : "1", "_class" : "com.mongo.model.Orders", "onumber" : "001", "date" :ISODate("2015-01-24T16:07:00Z"), "cname" : "zcy1", "items" : [ { "quantit y" : 5,"price" : 4, "pnumber" : "p001" }, { "quantity" : 6, "price" : 8, "pnumber" : "p002" } ] }
ObjectId值"_id": "1"已經存在,我們分別對Save和Insert方法新增文件時,指定已經存在"_id": "1"。
1.測試Insert方法新增
//測試Insert方法新增
@Test
public void testInsert() throws ParseException
{
SimpleDateFormat form=new SimpleDateFormat("yyyy-mm-dd");
//訂單
Orders order =new Orders();
order.setId("1");
order.setOnumber("002");
order.setDate(form.parse("2015-07-25"));
order.setCname("zcy2");
//訂單詳情
List<Item> items=new ArrayList<Item>();
Item item1=new Item();
item1.setPnumber("p003");
item1.setPrice(4.0);
item1.setQuantity(5);
items.add(item1);
Item item2=new Item();
item2.setPnumber("p003");
item2.setPrice(8.0);
item2.setQuantity(6);
items.add(item2);
order.setItems(items);
ordersDao.insert(order,collectionName);
}
我們新增相同的ID時,執行新增文件時,添加出現錯誤
org.springframework.dao.DuplicateKeyException:insertDocument :: caused by :: 11000 E11000 duplicate key error index:test.orders.$_id_ dup key: { :"1" }; nested exception is com.mongodb.MongoException$DuplicateKey:insertDocument :: caused by :: 11000 E11000 duplicate key error index:test.orders.$_id_ dup key: { :"1" }
呼叫持久層類的進行儲存域更新的時候,主鍵或唯一性約束衝突。
2.測試Save方法新增
//測試Save方法新增
@Test
public void testSave() throws ParseException
{
SimpleDateFormat form=new SimpleDateFormat("yyyy-mm-dd");
//訂單
Orders order =new Orders();
order.setId("1");
order.setOnumber("002");
order.setDate(form.parse("2015-07-25"));
order.setCname("zcy2");
//訂單詳情
List<Item> items=new ArrayList<Item>();
Item item1=new Item();
item1.setPnumber("p003");
item1.setPrice(4.0);
item1.setQuantity(5);
items.add(item1);
Item item2=new Item();
item2.setPnumber("p003");
item2.setPrice(8.0);
item2.setQuantity(6);
items.add(item2);
order.setItems(items);
ordersDao.save(order,collectionName);
}
我們新增相同的ID時,如果已經存在,會對相對應的文件進行更新,呼叫update更新裡面的文件。
> db.orders.find()
{ "_id" : "1", "_class" :"com.mongo.model.Orders", "onumber" : "002","date" :ISODate("2015-01-24T16:07:00Z"),"cname" : "zcy2", "items" : [ {"quantity" : 5,"price": 4, "pnumber" : "p003" }, { "quantity" : 6,"price" : 8, "pnumber" : "p003" } ] }
說明:
(1)save :我們在新增文件時,如果有一個相同_ID的文件時,會覆蓋原來的。
(2)insert:我們在新增文件時,如果有一個相同的_ID時,就會新增失敗。
(3)MongoDB提供了insertAll批量新增,可以一次性插入一個列表,效率比較高,save則需要一個一個的插入文件,效率比較低。三、刪除文件、刪除集合
1. 刪除文件
Spring Data MongoDB 的MongoTemplate提供刪除文件如下幾個方法:
1) 我們這邊重點根據條件刪除文件
第一步:我們在基礎介面MongoBase.java類新增一個根據條件刪除文件的介面 。
//根據條件刪除
public void remove(String field,String value,String collectionName);
第二步:我們在OrdersDaoImpl類新增一個具體根據條件刪除文件的實現方法。
@Override
public void remove(Map<String, Object> params,String collectionName) {
mongoTemplate.remove(new Query(Criteria.where("id").is(params.get("id"))),User.class,collectionName);
}
> db.orders.find()
{ "_id" : "1", "_class" : "com.mongo.model.Orders", "onumber" : "001", "date" :ISODate("2015-01-24T16:07:00Z"), "cname" : "zcy1", "items" : [ { "quantity" : 5,"price" : 4, "pnumber" : "p001" }, { "quantity" : 6, "price" : 8, "pnumber" : "p002" } ] }
{ "_id" : "2", "_class" : "com.mongo.model.Orders", "onumber" : "002", "date" :ISODate("2015-01-24T16:07:00Z"), "cname" : "zcy2", "items" : [ { "quantity" : 5,"price" : 4, "pnumber" : "p003" }, { "quantity" : 6, "price" : 8, "pnumber" : "p004" } ] }
>
現在查詢MongoDB有兩條文件
2)實現測試類
@Test
public void testRemove() throws ParseException
{
ordersDao.remove("onumber","002", collectionName);
}
我們根據onumber=002條件刪除文件
> db.orders.find()
{ "_id" : "1", "_class" : "com.mongo.model.Orders", "onumber" : "001", "date" :ISODate("2015-01-24T16:07:00Z"), "cname" : "zcy1", "items" : [ { "quantity" : 5,"price" : 4, "pnumber" : "p001" }, { "quantity" : 6, "price" : 8, "pnumber" : "p002" } ] }
只剩下onumber=001的文件。
刪除orders的資料,集合還存在,索引都還存在,相當與SQ的truncate命令。
2. 刪除集合
第一步:我們在基礎介面MongoBase.java類新增一個根據條件刪除集合的介面。
//刪除集合
public void dropCollection(String collectionName);
第二步:我們在OrdersDaoImpl類新增一個具體根據條件刪除集合的實現方法。
@Override
public void dropCollection(String collectionName) {
mongoTemplate.dropCollection(collectionName);
}
集合、索引都不存在了,型別SQL的drop。