<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
MyBatis 是⼀款優秀的持久層框架,它⽀持⾃定義 SQL、儲存過程以及⾼級對映。MyBatis 去除了很多JDBC 程式碼以及設定的引數和獲取結果集的工作。MyBatis 可以通過簡單的 XML 或註解來設定和對映原始型別、接⼝和 Java POJO (Plain Old Java Object。普通老式 Java物件)為資料庫中的記錄。
對於後端開發來說,程式是由兩個重要部分組成的:
1.後端程式
2.資料庫
⽽這兩個重要的組成部分要通訊,就要依靠資料庫連線⼯具
1.JDBC
2. MyBatis
JDBC 的操作流程:
1. 建立資料庫連線池 DataSource
2. 通過 DataSource 獲取資料庫連線 Connection
3. 編寫要執⾏帶 ? 預留位置的 SQL 語句
4. 通過 Connection 及 SQL 建立操作命令物件 Statement
5. 替換預留位置:指定要替換的資料庫欄位型別,預留位置索引及要替換的值
6. 使⽤ Statement 執⾏ SQL 語句
7. 查詢操作:返回結果集 ResultSet,更新操作:返回更新的數量
8. 處理結果集
9. 釋放資源
對於 JDBC 來說,整個操作⾮常的繁瑣,我們不但要拼接每⼀個引數,⽽且還要按照模板程式碼的⽅式,⼀步步的運算元據庫,並且在每次操作完,還要⼿動關閉連線等,⽽所有的這些操作步驟都需要在每個⽅法中重複書寫。 對於 MyBatis ,它可以幫助我們更⽅便、更快速的運算元據庫。
框架互動流程
MyBatis 也是⼀個 ORM 框架, ORM(Object Relational Mapping),即物件關係對映。在⾯向對 象程式設計語⾔中,將關係型資料庫中的資料與物件建⽴起對映關係,進⽽⾃動的完成資料與物件的互相轉換:
1. 將輸⼊資料(即傳⼊物件)+SQL 對映成原⽣ SQL
2. 將結果集對映為返回物件,即輸出物件ORM 把資料庫對映為物件:
資料庫表(table)--> 類(class)
記錄(record,⾏資料)--> 物件(object)
欄位(field) --> 物件的屬性(attribute)
⼀般的 ORM 框架,會將資料庫模型的每張表都對映為⼀個 Java 類。 也就是說使⽤ MyBatis 可以像操作物件⼀樣來運算元據庫中的表,可以實現物件和資料庫表之間的轉換。
使⽤ MyBatis 的⽅式來讀取⽤戶表中的所有⽤戶
建立使用者表
drop table if exists userinfo; create table userinfo( id int primary key auto_increment, username varchar(100) not null, password varchar(32) not null, photo varchar(500) default '', createtime datetime default now(), updatetime datetime default now(), `state` int default 1 ) default charset 'utf8mb4';
在建立新專案時,來到這一步,只需將下面的勾選即可
在 pom.xml 檔案頁面 滑鼠右鍵進行下面操作
將當前執行環境選擇開發環境的設定
application-dev.yml
#開發環境 #設定資料庫連線 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/myblog?characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver # 開啟 MyBatis SQL 列印 logging: level: com: example: demo: debug mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
application.yml
選擇開發環境
spring: profiles: active: dev
MyBatis 的 XML 中儲存是查詢資料庫的具體操作 SQL,設定在 application.yml 中
#設定mybatis xml 儲存路徑 mybatis: mapper-locations: classpsth:mybatis/**Mapper.xml
下⾯按照後端開發的⼯程思路,也就是下⾯的流程來實現 MyBatis 查詢所有⽤戶的功能
目錄結構:
先新增使用者實體類
/** * 普通使用者實體類 */ @Data public class UserInfo { private Integer id; private String name; private String password; private String photo; private String createtime; private String updatetime; private int state; }
資料持久層的介面定義:
/** * 實現資料庫對映 */ @Mapper public interface UserMapper { //查詢使用者 ID public UserInfo getUserById(@Param("id") Integer id); }
資料持久層的實現,mybatis 的固定 xml 格式
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace 要設定是實現介面的具體包名加類名 --> <mapper namespace="com.example.demo.mapper.UserMapper"> </mapper>
UserMapper.xml 查詢所有⽤戶的具體實現 SQL:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace 要設定是實現介面的具體包名加類名 --> <mapper namespace="com.example.demo.mapper.UserMapper"> <resultMap id="BaseMap" type="com.example.demo.model.UserInfo"> <!-- 主鍵對映 --> <id column="id" property="id"></id> <!-- 普通屬性對映 --> <result column="username" property="name"></result> </resultMap> <!-- 根據 id 查詢使用者 --> <select id="getUserById" resultMap="BaseMap"> select * from userinfo where id=${id} </select> </mapper>
標籤說明:
<mapper>標籤:需要指定 namespace 屬性,表示名稱空間,值為 mapper 接⼝的全限定名,包括全包名.類名。
<select>查詢標籤:是⽤來執⾏資料庫的查詢操作的:
決定呼叫哪個mapper
@Service public class UserService { @Resource private UserMapper userMapper; public UserInfo getUserById(Integer id) { return userMapper.getUserById(id); } }
@Controller @ResponseBody @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @RequestMapping("/getuserbyid") public UserInfo getUserById(Integer id) { if (id == null) return null; return userService.getUserById(id); } }
以上程式碼寫完,整個 MyBatis 的查詢功能就實現完了
在 UserMapper 中增加修改的程式碼
//修改方法根據 ID 修改名稱 public int update(@Param("id") Integer id, @Param("name") String username);
UserMapper.xml 中增加介面的實現標籤和具體的執行SQL
<update id="update" > update userinfo set username=#{name} where id=#{id} </update>
通過單元測試,實現成功
@Test void update() { int result = userMapper.update(2,"fei"); Assertions.assertEquals(1,result); }
查詢SQL語句可知,已經修改了
如果僅僅是為了測試功能是否實現,而不修改資料庫中的內容,可以加入註解 @Transactional
@Test @Transactional // 新增此註解後,執行完單元測試,不會修改資料庫中的內容,即事務回滾 void update() { int result = userMapper.update(2,"fei"); Assertions.assertEquals(1,result); }
在 UserMapper 中增加刪除的程式碼
//刪除方法 public int del(@Param("id") Integer id);
UserMapper.xml 中增加介面的實現標籤和具體的執行SQL
<!--刪除操作--> <delete id="del"> delete from userinfo where id=#{id}; </delete>
單元測試
@Test @Transactional void del() { int result = userMapper.del(2); System.out.println("刪除行數: " + result); Assertions.assertEquals(1,result); }
在 UserMapper 中新增增加的程式碼
//增加使用者方法 // 傳過來的是物件而不是某個成員變數 public int add(UserInfo userInfo);
UserMapper.xml 中增加介面的實現標籤和具體的執行SQL
<!--增加操作,返回受影響的行數--> <insert id="add"> insert into userinfo(username,password,photo) values(#{username}, #{password}, #{photo}); <!--和物件裡面的屬性一一對應--> </insert>
單元測試
@Test //@Transactional void add() { UserInfo userInfo = new UserInfo(); userInfo.setName("y"); userInfo.setPassword("123"); userInfo.setPhoto(""); System.out.println("新增之前的 id: " + userInfo.getId()); int result = userMapper.add(userInfo); System.out.println("新增之後的 id: " + userInfo.getId()); System.out.println("新增的行數: " + result); Assertions.assertEquals(1,result); }
在 UserMapper 中新增增加的程式碼
//新增使用者,返回自增ID public int addGetId(UserInfo userInfo);
UserMapper.xml 中增加介面的實現標籤和具體的執行SQL
<!--增加操作,返回受影響的行數和自增ID--> <insert id="addGetId" useGeneratedKeys="true" keyProperty="id" keyColumn="id"> insert into userinfo(username,password,photo) values(#{name}, #{password}, #{photo}); <!--和物件裡面的屬性一一對應--> </insert>
單元測試
@Test //@Transactional void addGetId() { UserInfo userInfo = new UserInfo(); userInfo.setName("yang"); userInfo.setPassword("123"); userInfo.setPhoto(""); System.out.println("新增之前的 id: " + userInfo.getId()); int result = userMapper.addGetId(userInfo); System.out.println("新增之後的 id: " + userInfo.getId()); System.out.println("新增的行數: " + result); Assertions.assertEquals(1,result); }
#{}:預編譯處理 。處理時,成一個 問號? ,賦值時會加上 單引號 ‘ ’
${}:字元直接替換
區別:
1.定義不同
預編譯處理是指:MyBatis 在處理#{}時,會將 SQL 中的 #{} 替換為?號,使⽤ PreparedStatement 的set ⽅法來賦值。
直接替換:是MyBatis 在處理 ${} 時,就是把 ${} 替換成變數的值。
2.使用不同:#{} 適用於所有型別的引數匹配,但${} 只適用於數值型別
3.安全性不同:#{} 效能高,並且沒有安全問題;但 ${} 存在SQL隱碼攻擊的安全問題
#{}:預編譯處理 預留位置,當成 value 值來使用, 即加上 ‘ ’
<select id="gerUserFullById" resultType="com.example.demo.model.UserInfo"> select * from userinfo where username=#{name} </select>
@Test void gerUserFullById() { UserInfo userInfo = userMapper.gerUserFullById("fei"); System.out.println("userInfo: " + userInfo); }
${}:字元直接替換
不加任何符合,直接替換上去,連成一個SQL 命令
<select id="gerUserFullById" resultType="com.example.demo.model.UserInfo"> select * from userinfo where username=${name} </select>
單元測試結果
//對使用者進行排序 public List<UserInfo> getOrderList(@Param("order") String order);
此處使用的是 ${}, 如果使用 #{} 的話,會編譯出錯,因為它會把 desc 當成 ‘desc’ 一個value 值來使用,不構成一個 SQL命令語句
<select id="getOrderList" resultType="com.example.demo.model.UserInfo"> select * from userinfo order by createtime ${order} </select>
單元測試
@Test void getOrderList() { List<UserInfo> list = userMapper.getOrderList("desc"); log.info("列表: " + list); }
//登入功能 public UserInfo login(@Param("name") String username, @Param("password") String password);
1) 在使用${} 時,需要加單引號,因為是直接替換
<select id="login" resultType="com.example.demo.model.UserInfo"> select * from userinfo where username='${name}' and password='${password}'; </select>
單元測試
@Test void login() { String username = "Fly"; String password = ""; UserInfo userInfo = userMapper.login(username,password); log.info("使用者資訊: " + userInfo); }
使用 " 'or 1=' 1" 時,SQL隱碼攻擊,密碼會洩露,如下,因此在登入時應使用#{}
@Test void login() { String username = "Fly"; //String password = ""; String password = "'or 1='1"; UserInfo userInfo = userMapper.login(username,password); log.info("使用者資訊: " + userInfo); }
2)#{} 預編譯處理,不會出現密碼洩露
<!--登入功能--> <select id="login" resultType="com.example.demo.model.UserInfo"> <!--select * from userinfo where username='${name}' and password='${password}'; --> select * from userinfo where username=#{name} and password=#{password}; </select>
//like 模糊查詢 public List<UserInfo> getUserByName(@Param("name") String username);
1)直接使用 #{} 會報錯
因為賦值時會加上單引號 ‘’
select * from userinfo where username like '%#{name}%'
就相當於下面的語句,不符合查詢條件
select * from userinfo where username like '%'name'%'
2)使用${} 是不會報錯,但在業務層的值不能窮舉
3)#{} 在like中的正確用法,加上contat 拼接,演示如下
正確用法
因為#{} 在賦值的時候,會帶上單引號‘’ ,所以下面的#{}不需要帶單引號
<!--like 模糊查詢--> <select id="getUserByName" resultType="com.example.demo.model.UserInfo"> <!-- select * from userinfo where username like '%#{name}%'--> select * from userinfo where username like concat('%',#{name},'%') </select>
單元測試
@Test void getUserByName() { String username = "l"; List<UserInfo> list= userMapper.getUserByName(username); log.info("使用者列表: " + list); }
絕大數查詢場景可以使用 resultType 進行返回,如下
<!-- 根據 id 查詢使用者 --> <select id="getUserById" resultType="com.example.demo.model.UserInfo"> select * from userinfo where id=${id} </select>
它的優點是使⽤⽅便,直接定義到某個實體類即可 6.2 返回字典對映:resultMap 使用場景:
欄位名稱和程式中的屬性名不同的情況, 可使⽤ resultMap 設定對映; 一對一和一對多關係可以使用 resultMap 對映並查詢資料
1)欄位名程式中的屬性名不一致
userMapper.xml 程式碼如下
<!-- 根據 id 查詢使用者 --> <select id="getUserById" resultType="com.example.demo.model.UserInfo"> select * from userinfo where id=${id} </select>
查詢結果
這個時候就可以使⽤ resultMap 了,resultMap 的使⽤如下
userMapper.xml 程式碼如下
<resultMap id="BaseMap" type="com.example.demo.model.UserInfo"> <!--主鍵對映--> <id column="id" property="id"></id> <!--普通屬性對映--> <result column="username" property="name"></result> <result column="password" property="password"></result> <result column="photo" property="photo"></result> <result column="createtime" property="createtime"></result> <result column="updatetime" property="updatetime"></result> </resultMap> <!-- 根據 id 查詢使用者 --> <select id="getUserById" resultMap="BaseMap"> select * from userinfo where id=${id} </select>
單元測試
@Test void getUserById() { UserInfo userInfo = userMapper.getUserById(1); //Assertions.assertNotNull(userInfo); log.info("查詢行數:" + userInfo); }
查詢結果
建立文章實體類 ArticleInfo
@Data public class ArticleInfo { private int id; private String title; private String content; private String createtime; private String updatetime; private int uid; private int rcount; private int state; private UserInfo userInfo; }
mapper 實現資料庫對映 ArticleMapper
@Mapper public interface ArticleMapper { //根據文章 id 獲取文章 public ArticleInfo getArticleById(@Param("id") Integer id); //文章id }
資料庫命令,資料持久層的實現, ArticleMapper.xml
<mapper namespace="com.example.demo.mapper.ArticleMapper"> <resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo"> <!--主鍵對映--> <id column="id" property="id"></id> <!--普通屬性對映--> <result column="title" property="title"></result> <result column="content" property="content"></result> <result column="createtime" property="createtime"></result> <result column="uid" property="uid"></result> <result column="rcount" property="rcount"></result> <result column="state" property="state"></result> <association property="userInfo" resultMap="com.example.demo.mapper.UserMapper.BaseMap" columnPrefix="u_"></association> </resultMap> <select id="getArticleById" resultMap="BaseMap"> select a.*,u.* from articleinfo a left join userinfo u on a.uid=u.id </select> </mapper>
以上使⽤ <association>標籤,表示⼀對⼀的結果對映:
property 屬性:指定 Article 中對應的屬性,即⽤戶。
resultMap 屬性:指定關聯的結果集對映,將基於該對映設定來組織⽤戶資料。
columnPrefix 屬性:繫結⼀對⼀物件時,因為對應的是使用者表 ,所以是“u-”是通過 columnPrefix+association.resultMap.column 來對映結果集欄位。 association.resultMap.column是指 <association>標籤中 resultMap屬性,對應的結果集對映中,column欄位
單元測試
//將類屬性注入 @Resource private ArticleMapper articleMapper; @Test void getArticleById() { ArticleInfo articleInfo = articleMapper.getArticleById(1); log.info("查詢結果:" + articleInfo ); }
查詢結果
一個使用者對應多篇文章
實體類
@Data public class UserInfo { private Integer id; //private String username;//用於resultType private String name; //用於 resultMap private String password; private String photo; private String createtime; private String updatetime; private int state; //一對多 private List<ArticleInfo> artlist; }
mapper
//一對多,多表查詢 //根據使用者 id 查詢使用者及使用者發表的所有文章 public UserInfo getUserAndArticleByUid(@Param("uid") Integer uid);
XML
<resultMap id="BaseMap" type="com.example.demo.model.UserInfo"> <!--主鍵對映--> <id column="id" property="id"></id> <!--普通屬性對映--> <result column="username" property="name"></result> <result column="password" property="password"></result> <result column="photo" property="photo"></result> <result column="createtime" property="createtime"></result> <result column="updatetime" property="updatetime"></result> <result column="state" property="state"></result> <!--多表查詢--> <collection property="artlist" resultMap="com.example.demo.mapper.ArticleMapper.BaseMap" columnPrefix="a_"> </collection> </resultMap> <!--多表查詢--> <select id="getUserAndArticleByUid" resultMap="BaseMap"> select u.*,a.id a_id,a.title a_title,a.content a_content, a.createtime a_createtime, a.updatetime a_updatetime from userinfo u left join articleinfo a on u.id=a.uid where u.id=#{uid} </select>
單元測試
@Test void getUserAndArticleByUid() { UserInfo userInfo = userMapper.getUserAndArticleByUid(1); log.info("使用者詳情:" + userInfo); }
動態SQL是mybatis 的強大特性之一,能夠完成不同條件的SQL拼接
在填寫個人資訊時,會經常遇到一些必填項,一些非必填項,如下
註冊分為兩種欄位:必填欄位和⾮必填欄位,那如果在新增⽤戶的時候有不確定的欄位傳⼊,程式應該如何實現呢? 這個時候就需要使⽤動態標籤 <if> 來判斷了:
判斷一個引數是否有值,如果沒值,就會隱藏 if 中的SQL
現在有一張使用者表
在新增使用者的時候,將 photo 設為非比傳引數
1)傳入photo 時
mapper
//動態SQL,新增使用者,photo為非必傳引數 public int add2(UserInfo userInfo);
UserMapper.xml
<!--動態SQL,新增使用者--> <insert id="add2"> insert into userinfo(username,password <if test="photo !=null"> ,photo </if> ) values(#{name}, #{password} <if test="photo !=null"> , #{photo} </if> ) </insert>
注意 test 中的 photo 和 #{},是傳⼊物件中的屬性,不是資料庫欄位
單元測試
@Test void add2() { UserInfo userInfo = new UserInfo(); userInfo.setName("楊通"); userInfo.setPassword("123"); userInfo.setPhoto("123.jpg"); int result = userMapper.add2(userInfo); log.info("新增使用者:" + result); }
新增結果
2)不傳入 photo 時
不用像沒使用動態SQL時,將 userInfo.setPhoto(""); 設為空,直接忽略不寫就行了
@Test void add2() { UserInfo userInfo = new UserInfo(); userInfo.setName("黃空"); userInfo.setPassword("123"); //userInfo.setPhoto("123.jpg"); int result = userMapper.add2(userInfo); log.info("新增使用者:" + result); }
動態SQL直接忽略photo,新增成功
最主要的作用:去除SQL語句前後多餘的某個字元
語法:
<trim>標籤中有如下屬性:
prefix: 表示這個語句快,以prefix的值作為字首
suffix:表示整個語句塊,以suffix的值作為字尾
prefixOverrides:表示整個語句塊要去除掉的字首
suffixOverrides:表示整個語句塊要去除掉的字尾
UserMapper
//動態SQL, <trim> 標籤。新增使用者,photo為非必傳引數 public int add3(UserInfo userInfo);
UserMapper.xml
<!--動態SQL,<trim> 標籤。新增使用者--> <insert id="add3"> insert into userinfo <trim prefix="(" suffix=")" suffixOverrides=","> <if test="name != null"> <!--這裡拼接的是資料庫中的欄位--> username, </if> <if test="password != null"> password, </if> <if test="photo != null"> photo </if> </trim> values <trim prefix="(" suffix=")" suffixOverrides=","> <if test="name != null"> #{name}, </if> <if test="password != null"> #{password}, </if> <if test="photo != null"> #{photo} </if> </trim> </insert>
單元測試
這裡不傳photo,看拼接的欄位前的一個逗號是否還在
@Test void add3() { UserInfo userInfo = new UserInfo(); userInfo.setName("黃小小"); userInfo.setPassword("123"); //userInfo.setPhoto("123.jpg"); 這裡不傳,看拼接的欄位前的一個逗號是否還在 int result = userMapper.add2(userInfo); log.info("新增使用者:" + result); }
主要作用:實現查詢中的 where SQL替換,它可以實現如果沒有任何的查詢條件,那麼他可以因此查詢中的 where SQL ,但如果存在查詢中條件,那麼會生成where的 SQL查詢,並且使用 where 標籤可以自動的去除最後一個 and字元。
1)SQL 替換
根據 id 查詢使用者:
<!-- 根據 id 查詢使用者 --> <select id="getUserById" resultMap="BaseMap"> select * from userinfo <where> <if test="id != null"> id=#{id} </if> </where> </select>
當傳入的 id 為 null 時
@Test void getUserById() { UserInfo userInfo = userMapper.getUserById(null); //Assertions.assertNotNull(userInfo); log.info("查詢行數:" + userInfo); }
2)去除 and
或者通過 id 或者 username 來查詢時,如果username 為空就會去掉
作用:進行修改操作是,配合 if 來處理非必傳欄位,他的特點是主動去除最後一個英文逗號
語法:
update table_name <set> <if test="xxx"> ... </if> ... </set> where ...
1)修改使用者名稱
UserMapper
//動態SQL, <set> 標籤。修改使用者 public int update2(UserInfo userInfo);
UserMapper.xml
<update id="update2"> update userinfo <set> <if test="name != null"> username=#{name}, </if> <if test="password != null"> password = #{password}, </if> <if test="photo != null"> photo = #{photo} </if> </set> </update>
單元測試
@Test void update2() { UserInfo userInfo = new UserInfo(); userInfo.setId(1); //查詢 id 為 1 的使用者 userInfo.setName("fei"); // 將使用者名稱修改為 fei int result = userMapper.update2(userInfo); log.info("修改結果: " + result); }
對集合進⾏遍歷時可以使⽤該標籤。<foreach>標籤有如下屬性:
collection: 繫結方法引數中的集合,如List 、Set、Map或陣列物件
item: 遍歷時的每一個物件
open:語句塊開頭的字串
close:語句塊結束的字串
separator:每次遍歷之間間隔的字串
範例:根據使用者 id 來對使用者進行刪除
UserMapper
//動態SQL,<foreach>,刪除多個使用者 public int delId(List<Integer> ids);
UserMapper.xml
<!--動態SQL,刪除多個使用者--> <delete id="delId"> delete from userinfo where id in <foreach collection="ids" open="(" close=")" item="id" separator=","> #{id} </foreach> </delete>
單元測試
@Test void delId() { List<Integer> list = new ArrayList<>(); list.add(2); list.add(3); list.add(4); int result = userMapper.delId(list); log.info("刪除的行數:" + result); }
結果
到此這篇關於MyBatis後端對資料庫進行增刪改查等操作的文章就介紹到這了,更多相關MyBatis後端對資料庫操作內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45