MyBatis初級實戰之二:增刪改查

2020-08-29 程式設計師欣宸

本文是《MyBatis初級實戰》系列的第二篇,前文《 》我們知道了如何在SpringBoot中集成MyBatis,本篇就一起來練習基本功:增刪改查;

本篇概覽

本篇要練習的內容如下:

  1. 單表的增刪改查
  2. 批量新增
  3. 聯表查詢

全文由以下部分組成:

  1. 新建工程
  2. 增加啟動類
  3. 增加swagger的配置類,工程包含了swagger,以便稍後在瀏覽器上驗證
  4. 增加配置文件
  5. 增加實體類
  6. 增加mapper配置文件
  7. 增加mapper接口
  8. 增加service,調用mapper接口
  9. 增加controller,調用service服務
  10. 編寫單元測試用例
  11. 驗證

源碼下載

  • 如果您不想編碼,可以在GitHub下載所有源碼,地址和連結信息如下表所示(
    https://github.com/zq2599/blog_demos):
    • 這個git項目中有多個文件夾,《MyBatis初級實戰》系列的源碼在mybatis文件夾下,如下圖紅框所示:

    開發

    • 本文的實戰使用的資料庫和表結構與前文《 》一模一樣;
    • 前文《 》新建了父工程mybatis,本文繼續在此工程中新增子工程,名為curd,整個子工程文件結構如下:

    • 修改父工程mybatis的pom.xml,在dependencyManagement節點下新增兩個dependency節點,如下所示,這麼做是為了統一管理依賴庫的版本:

    <!-- swagger-ui --><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.5.0</version></dependency><dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version></dependency>

    • 名為curd子工程,其pom.xml內容如下:

    <?xml version=&34; encoding=&34;?><project xmlns=&34; xmlns:xsi=&34; xsi:schemaLocation=&34;> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.bolingcavalry</groupId> <artifactId>mybatis</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <groupId>com.bolingcavalry</groupId> <artifactId>curd</artifactId> <version>0.0.1-SNAPSHOT</version> <name>curd</name> <description>Demo project for Mybatis CURD in Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> </dependency> <!-- swagger-ui --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>

    • 增加啟動類,注意要用MapperScan註解來指定mapper接口代碼的包路徑:

    package com.bolingcavalry.curd;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication@MapperScan(&34;)public class CurdApplication { public static void main(String[] args) { SpringApplication.run(CurdApplication.class, args); }}

    • 本次實戰用到了swagger,這樣可以很方便的通過瀏覽器向各個controller接口發送請求,以下是swagger配置類:

    package com.bolingcavalry.curd;import springfox.documentation.service.Contact;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.service.Tag;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration@EnableSwagger2public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .tags(new Tag(&34;, &34;), new Tag(&34;, &34;)) .select() // 當前包路徑 .apis(RequestHandlerSelectors.basePackage(&34;)) .paths(PathSelectors.any()) .build(); } //構建 api文檔的詳細信息函數,注意這裡的註解引用的是哪個 private ApiInfo apiInfo() { return new ApiInfoBuilder() //頁面標題 .title(&34;) //創建人 .contact(new Contact(&34;, &34;, &34;)) //版本號 .version(&34;) //描述 .description(&34;) .build(); }}

    • application.yml內容如下:

    server: port: 8080spring: mybatis配置mybatis: 映射文件所在位置 mapper-locations: classpath:mappers/*Mapper.xml34;用戶實體類&34;用戶ID&34;用戶名&34;用戶地址&34;User{&34;id=&34;, name=&34; + name + &39;&34;, age=&39;}&34;日誌實體類&34;日誌ID&34;用戶ID&34;日誌內容&34;創建時間&34;Log{&34;id=&34;, userId=&34;, action=&34; + action + &39;&34;, createTime=&39;}&34;日誌實體類(含用戶表的欄位)&34;用戶名&34;LogExtend{&34;id=&34;, userId=&34;, userName=&34; + getUserName() + &39;&34;, action=&34; + getAction() + &39;&34;, createTime=&39;}&34;1.0&34;UTF-8&34;-//mybatis.org//DTD Mapper 3.0//EN&34;http://mybatis.org/dtd/mybatis-3-mapper.dtd&34;com.bolingcavalry.curd.mapper.UserMapper&34;sel&34;int&34;user&{id} </select> <!--新增單條記錄--> <insert id=&34; useGeneratedKeys=&34; keyProperty=&34;> insert into user (id, name, age) values ({name}, 34;insertBatch&34;true&34;id&34;users&34;user&34;,&{user.id}, {user.age}) </foreach> </insert> <!--按照名稱查找--> <select id=&34; parameterType=&34; resultType=&34;> select id, name, age from user where name like concat(&39;, 39;%&34;delete&{id} </delete> <!--刪除所有數據--> <delete id=&34;> delete from user </delete> <!--更新--> <update id=&34;> update user set name = {age} where id = 34;totalCount&34;java.lang.Integer&34;1.0&34;UTF-8&34;-//mybatis.org//DTD Mapper 3.0//EN&34;http://mybatis.org/dtd/mybatis-3-mapper.dtd&34;com.bolingcavalry.curd.mapper.LogMapper&34;logExtendResultMap&34;logExtend&34;id&34;id&34;user_id&34;INTEGER&34;userId&34;action&34;VARCHAR&34;action&34;create_time&34;TIMESTAMP&34;createTime&34;user_name&34;TIMESTAMP&34;userName&34;insertWithFields&34;true&34;id&34;log&{id}, {action}, 34;selExtend&34;int&34;logExtendResultMap&{id} </select></mapper>

    • 增加用戶表的mapper接口類UserMapper.java ,對應著映射文件中的sql節點的id:

    package com.bolingcavalry.curd.mapper;import com.bolingcavalry.curd.entity.LogExtend;import com.bolingcavalry.curd.entity.User;import org.springframework.stereotype.Repository;import java.util.List;@Repositorypublic interface UserMapper { User sel(int id); int insertWithFields(User user); int insertBatch(List<User> users); int clearAll(); List<User> findByName(String name); int update(User user); int delete(int id); int totalCount(); LogExtend selExtend(int id);}

    • 增加日誌表的mapper接口類LogMapper.java,對應著映射文件中的sql節點的id:

    package com.bolingcavalry.curd.mapper;import com.bolingcavalry.curd.entity.Log;import com.bolingcavalry.curd.entity.LogExtend;import org.springframework.stereotype.Repository;@Repositorypublic interface LogMapper { Log sel(int id); LogExtend selExtend(int id); int insertWithFields(Log log);}

    • mapper接口完成後就是service層,先寫user表的service,如下所示,可見都是對mapper接口的調用:

    package com.bolingcavalry.curd.service;import com.bolingcavalry.curd.entity.User;import com.bolingcavalry.curd.mapper.UserMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;@Servicepublic class UserService { @Autowired UserMapper userMapper; public User sel(int id) { return userMapper.sel(id); } public User insertWithFields(User user) { userMapper.insertWithFields(user); return user; } public List<User> insertBatch(List<User> users) { userMapper.insertBatch(users); return users; } public int clearAll() { return userMapper.clearAll(); } public List<User> findByName(String name) { return userMapper.findByName(name); } public int update(User user) { return userMapper.update(user); } public int delete(int id) { return userMapper.delete(id); } public int totalCount() { return userMapper.totalCount(); }}

    • 還有log表的service:

    package com.bolingcavalry.curd.service;import com.bolingcavalry.curd.entity.Log;import com.bolingcavalry.curd.entity.LogExtend;import com.bolingcavalry.curd.entity.User;import com.bolingcavalry.curd.mapper.LogMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class LogService { @Autowired LogMapper logMapper; public Log sel(int id){ return logMapper.sel(id); } public LogExtend selExtend(int id) { return logMapper.selExtend(id); } public Log insertWithFields(Log log) { logMapper.insertWithFields(log); return log; }}

    • 最後是controller層了,由於使用了swagger,導致controller相對上一篇略微複雜(多了些註解):

    package com.bolingcavalry.curd.controller;import com.bolingcavalry.curd.entity.User;import com.bolingcavalry.curd.service.UserService;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.ArrayList;import java.util.List;@RestController@RequestMapping(&34;)@Api(tags = {&34;})public class UserController { @Autowired private UserService userService; @ApiOperation(value = &34;, notes=&34;) @RequestMapping(value = &34;,method = RequestMethod.PUT) public User create(@RequestBody User user) { return userService.insertWithFields(user); } @ApiOperation(value = &34;, notes=&34;) @RequestMapping(value = &34;, method = RequestMethod.PUT) public List<User> insertBatch(@RequestBody List<User> users) { return userService.insertBatch(users); } @ApiOperation(value = &34;, notes=&34;) @ApiImplicitParam(name = &34;, value = &34;, paramType = &34;, required = true, dataType = &34;) @RequestMapping(value = &34;, method = RequestMethod.DELETE) public int delete(@PathVariable int id){ return userService.delete(id); } @ApiOperation(value = &34;, notes=&34;) @RequestMapping(value = &34;, method = RequestMethod.DELETE) public int clearAll(){ return userService.clearAll(); } @ApiOperation(value = &34;, notes=&34;) @RequestMapping(value = &34;, method = RequestMethod.POST) public int update(@RequestBody User user){ return userService.update(user); } @ApiOperation(value = &34;, notes=&34;) @ApiImplicitParam(name = &34;, value = &34;, paramType = &34;, required = true, dataType = &34;) @RequestMapping(value = &34;, method = RequestMethod.GET) public List<User> findByName(@PathVariable(&34;) String name){ return userService.findByName(name); } @ApiOperation(value = &34;, notes=&34;) @ApiImplicitParam(name = &34;, value = &34;, paramType = &34;, required = true, dataType = &34;) @RequestMapping(value = &34;, method = RequestMethod.GET) public User GetUser(@PathVariable int id){ return userService.sel(id); } @ApiOperation(value = &34;, notes=&34;) @RequestMapping(value = &34;, method = RequestMethod.GET) public int totalcount(){ return userService.totalCount(); }}

    • log的controller如下:

    package com.bolingcavalry.curd.controller;import com.bolingcavalry.curd.entity.Log;import com.bolingcavalry.curd.entity.LogExtend;import com.bolingcavalry.curd.service.LogService;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;@RestController@RequestMapping(&34;)@Api(tags = {&34;})public class LogController { @Autowired private LogService logService; @ApiOperation(value = &34;, notes=&34;) @ApiImplicitParam(name = &34;, value = &34;, paramType = &34;, required = true, dataType = &34;) @RequestMapping(value = &34;, method = RequestMethod.GET) public LogExtend logExtend(@PathVariable int id){ return logService.selExtend(id); } @ApiOperation(value = &34;, notes=&34;) @RequestMapping(value = &34;,method = RequestMethod.PUT) public Log create(@RequestBody Log log) { return logService.insertWithFields(log); }}

    • 最後是一段單元測試的代碼,咱們試試通過junit進行自測,如下所示,可見一共測試了三個controller接口:先新增,再查找,最後刪除,要注意的是MockMvc的用法,以及jsonPath方法的用法,還有就是通過Order註解控制執行順序(一定要添加TestMethodOrder註解,否則Order註解不生效):

    package com.bolingcavalry.curd.controller;import com.bolingcavalry.curd.entity.User;import com.google.gson.Gson;import com.google.gson.JsonArray;import com.google.gson.JsonParser;import org.junit.Ignore;import org.junit.jupiter.api.*;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.http.MediaType;import org.springframework.test.context.junit4.SpringRunner;import org.springframework.test.web.servlet.MockMvc;import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;import java.util.List;import java.util.UUID;import static org.hamcrest.Matchers.hasSize;import static org.hamcrest.Matchers.is;import static org.hamcrest.core.IsEqual.equalTo;import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringRunner.class)@SpringBootTest@AutoConfigureMockMvc@TestMethodOrder(MethodOrderer.OrderAnnotation.class)class UserControllerTest { @Autowired private MockMvc mvc; // user表的name欄位,這裡為了保證測試時新增和刪除的記錄是同一條,用UUID作為用戶名 static String testName; @BeforeAll static void init() { testName = UUID.randomUUID().toString().replaceAll(&34;,&34;);; } @Test @Order(1) void insertWithFields() throws Exception { String jsonStr = &34;name\&34;&34;\&34;age\&34;; mvc.perform( MockMvcRequestBuilders.put(&34;) .contentType(MediaType.APPLICATION_JSON) .content(jsonStr) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath(&34;, is(testName))) .andDo(print()) .andReturn() .getResponse() .getContentAsString(); } @Test @Order(2) void findByName() throws Exception { mvc.perform(MockMvcRequestBuilders.get(&34;+ testName).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath(&34;, hasSize(1))) .andDo(print()); } @Test @Order(3) void delete() throws Exception { // 先根據名稱查出記錄 String responseString = mvc.perform(MockMvcRequestBuilders.get(&34;+ testName).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath(&34;, hasSize(1))) .andDo(print()) .andReturn() .getResponse() .getContentAsString(); // 反序列化得到數組 JsonArray jsonArray = JsonParser.parseString(responseString).getAsJsonArray(); // 反序列化得到user實例 User user = new Gson().fromJson(jsonArray.get(0), User.class); // 執行刪除 mvc.perform(MockMvcRequestBuilders.delete(&34;+ user.getId()).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().string(equalTo(&34;))) .andDo(print()); }}

    • 至此編碼結束,開始驗證上述功能;

    單元測試驗證

    • IDEA打開UserControllerTest.java,點擊下圖紅框中的圖標即可開始執行單元測試:

    • 單元測試完成後IDEA會給出結果,如下圖,紅框右側可以查看詳細的測試過程數據:

    • 篇幅所限,這隻有少量的單元測試用例,接下來用swagger來驗證每個接口;

    swagger驗證web接口

    • 如下圖,啟動CurdApplication類:

    • 瀏覽器訪問:http://localhost:8080/swagger-ui.html ,即可打開swagger頁面,如下圖:

    • 先試試新增的接口,操作如下圖:

    • 點擊了上圖紅框3的Try it out!按鈕後,響應信息如下圖,可見操作成功:

    • 限於篇幅,其他接口的測試就不逐一列出了,請您自行驗證;

    至此,MyBatis的基本增刪改查和簡單的聯表操作的實戰就完成了,接下來的文章咱們會繼續探索MyBatis的基本操作;

    歡迎關注我的公眾號:程式設計師欣宸

    相關焦點

    • 使用mybatis框架,完成增刪改查操作
      mybatis框架的繼續學習,安排如下:對昨天學習的內容做個小結,其中補充一個昨天忽視的問題。資料庫無外乎就是增刪改查,所以使用mybatis做一個完整的crud操作。最後使用動態代理對代碼優化,具體底層實現原理就不仔細深究了,大致知道怎麼回事就行。一、mybatis使用步驟回顧主要是涉及到配置文件的編寫,其中又包含核心配置文件和映射文件。
    • MyBatis初級實戰之一:Spring Boot集成
      github.com/zq2599/blog_demos內容:所有原創文章分類匯總及配套源碼,涉及Java、Docker、Kubernetes、DevOPS等;MyBatis初級實戰《MyBatis初級實戰》系列旨在通過一系列編碼實戰,和讀者一起掌握MyBatis的基本用法,幫助初學者快速運用MyBatis參與實際開發;聚焦MyBatis《MyBatis初級實戰》面向的是對MyBatis有興趣的讀者,向讀者們提供可用的方案和代碼,這裡不是比較Hibernate、sqltoy-orm
    • MyBatis初級實戰之三:集成druid
      初級實戰》系列的第三篇,我們將實戰springboot、mybatis、druid的集成,並驗證,由以下內容組成:新建springboot工程,裡面有詳細的集成druid的操作;編寫和執行單元測試代碼,並規避一個由集成druid帶來的問題;啟動springboot應用,通過swagger驗證基本功能正常;
    • Springboot+MybatisPlus高效實現增刪改查
      二、代碼生成器Mybatis-plus代碼生成器用於生成一個集成了Mybatis-plus的框架結構,一般會生成以下幾個文件。entity實體類:對應資料庫中的表的實體類,有各種Mybatis-plus的註解可以使用,比如主鍵生成策略、邏輯刪除、自動填充等。
    • MyBatis初級實戰之四:druid多數據源
      初級實戰》系列的第四篇,一個springboot應用同時操作兩個資料庫的場景,在平時也會遇到,今天要實戰的就是通過druid配置兩個數據源,讓一個springboot應用同時使用這兩個數據源;多數據源配置的基本思路首先要明確的是:數據源是通過配置類實現的,因此要去掉springboot中和數據源相關的自動裝配
    • MyBatis初級實戰之六:一對多關聯查詢
      https://github.com/zq2599/blog_demos內容:所有原創文章分類匯總及配套源碼,涉及Java、Docker、Kubernetes、DevOPS等;本篇概覽本文是《MyBatis初級實戰
    • D3.JS的增刪改查——數據的「三板斧」(下)
      在上一篇已經講述了數據可視化的偉大前景(D3.JS——展現數據最炫麗的一面)以及D3作為可視化一大發展趨勢最重要的操作——查(D3.JS的增刪改查——數據的「三板斧」之查),在可視化的指導下,本篇在能夠找到可視化內容的基礎上,實現D3.JS版的數據內容增刪改。
    • 精講Mybatis框架對資料庫增刪改查操作
      user表見名之意,通常用來儲存用戶的個人信息,可能用於登錄或其他統計信息,常見的欄位有id,用戶名,密碼,姓名,年齡,性別等,根據不同項目進行不同劃分。在項目開發中我們會做一種底層方法抽取來實現不同條件的增刪改查。下面請看java代碼很簡單只有兩行代碼。下面請看執行結果刷新navicat,可以看到表中id為30的章子怡已經被刪除了。以上就是我們通過MyBatis框架對資料庫進行基本的增刪改查操作。大家學習中有什麼疑問一定要在下方積極留言回復,有問必答。
    • MyBatis初級實戰之五:一對一關聯查詢
      初級實戰》系列的源碼在mybatis文件夾下,如下圖紅框所示:create_time) VALUES (7, 3, 'write', '2020-10-08 09:21:11');本次實戰的java工程在父工程mybatis下新建子工程relatedoperation,pom.xml如下:
    • SpringBoot整合MongoDB實現增刪改查(完整案例)
      自己本科時候一直使用的是Mysql,目前的課題組使用的是MongoDB,因此就花了一部分時間整理了一下,實現springboot與MongoDB的整合,並且實現基本的增刪改查操作,從頭到尾給出一個完整的案例。
    • spring boot項目集成mybatis-plus之常用註解之條件構造器二
      1 創建一個集成了mybatis-plus的項目項目總體工程目錄如下圖,可參考上一篇文章。基於Spring Boot整合mybatis-plus完整詳細版經驗分享一2 常用註解MyBatisPlus提供了一些註解供我們在實體類和表信息出現不對應的時候使用。通過使用註解完成邏輯上匹配。
    • mybatis plus自動填充屬性保存資料庫
      mybatis plus基於mybatis做了一層封裝,可以非常方便的對資料庫單表進行增刪改查,可以使用官方的api或者一些ide的插件進行自動生成代碼,主要有以下幾個部分的文件:entity類:對應資料庫的一張表,後續增刪改查也就是操作這個entity即可mapper接口:操作entity的一個封裝接口,封裝了一些常用的增刪改查方法,一個mapper
    • mybatis-plus思維導圖,讓mybatis-plus不再難懂
      但mybatis有個讓我比較頭疼的一個問題是sql工作量很大,尤其是欄位多的時候。雖然說單表的增刪改查操作可以通過mybatis generator工具來生成(或者自己寫模板工具生成),但項目開發的過程中總免不了要新添加新欄位,這些工具就幫不了我了,我得把新欄位寫到原來的所有增刪改查的sql中。這是個痛苦的過程,特別是當你重複了很多次之後。
    • 不是吧,你還在使用MyBatis Generator?試試這個工具吧
      代碼生成在企業軟體開發過程中,大多數時間都是面向資料庫表的增刪改查開發。通過通用的增刪改查代碼生成器,可以有效的提高效率,降低成本;把有規則的重複性勞動讓機器完成,解放開發人員。<plugin>    <groupId>org.mybatis.generator</groupId>    <artifactId>mybatis-generator-maven-plugin</artifactId> 
    • Mybatis-Plus和Mybatis你了解多少呢?
      通俗來講——MyBatis:一種操作資料庫的框架,提供一種Mapper類,支持讓你用java代碼進行增刪改查的資料庫操作,省去了每次都要手寫sql語句的麻煩。但是!有一個前提,你得先在xml中寫好sql語句,是不是很麻煩?
    • asp.net連接MySQL,在GridView上實現增刪改查:前臺配置參數實現
      asp.net中如果想要在GridView控制項上實現增刪改查,通過給GridView添加數據源就可以實現,前提是使用的資料庫必須是數據源中有的。啟用編輯和刪除二、給SqlDataSource配置ConnectionString屬性和ProviderName屬性,分別指定連接字符串和指定數據提供程序。
    • Axure9原型設計:動態面板實現頁面增刪改查模式彈窗效果
      本文作者就針對Axure9,談了談動態面板如何實現頁面增刪改查模式彈窗效果。其實相類似的文章很多,只是發現在9.0的版本下,沒有示例,所以做了一個簡單的示例說明。區別於8.0的版本,Axure9.0一些細節的改變讓人感覺陌生了些。
    • D3.JS的增刪改查——數據的「三板斧」之查
      這麼重要和寶貴的社會資源是人們通過何種方式完成了對它的挖掘和使用呢——這就是數據最具威力的手段,增刪改查;通過這四個方式形成的數據處理,展開了數據基礎上大規模的應用。數據操作之查隨著數據量的極速增長,數據的查找已經成為了一個越來越難的事情了,通過對d3對數據的查找分析,發現D3的查找是基於文檔樹實現的,其類似於CSS中的樣式定位,查找的對象主要是由標籤、id標識、class標識等三個部分組成
    • 阿里技術官十年經驗,寫出的Mybatis筆記,完整版免費下載
      本文介紹的是阿里資深架構師十年經驗整理,Mybatis頂級學習筆記,從原始的JDBC談起,深入淺出講解Mybatis實戰技巧。由於筆記內容偏多,篇幅受限,只能在文章中展示部分的章節內容和核心截圖,如果你需要完整的PDF版本,可以私信我關鍵詞【進階】免費領取。