一篇文章帶你了解并使用mybatis框架

mybatis簡介:

MyBatis 是一款優秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射。MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為數據庫中的記錄。

mybatis的優點:
mybatis框架內可以簡化數據據編程。mybatis底層封裝的是jdbc,使用起來大大簡化了jdbc。sql與java編碼分開,功能邊界清晰。

mybatis環境搭建:

開發環境:

maven

mysql8

創建maven項目,在pom.xml 中導入坐標依賴

<!-- junit單元測試 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- mysql驅動 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>

jar包的下載方式:

如果不使用maven,可以從官網上面下載相應的jar包,導入進行使用

https://github.com/mybatis/mybatis-3/releases

mybatis中文文檔:
https://mybatis.net.cn/index.html

mybatis核心原理:

什么叫ORM

ORM是Object Relational Mapping 對象關系映射。把數據庫表和實體類以及實體類的屬性對應起來,讓開發者操作實體類就實現操作數據表

ORM:也叫對象關系映射,是一種程序設計思想。簡單來說就是將數據庫中查詢出的數據映射到對應的實體中。

程序分層:
控制層:controller/servlet
業務邏輯層:service
持久層(數據庫訪問層):dao/mapper

mybatis操作數據庫的步驟:

①讀取mybatis的配置文件mybatis-cinfig.xml 是mybatis的全局配置文件,主要作用是獲取數據庫連接
②加載映射mapper.xml 該文件配置了操作數據庫的sql語句,需要在mybatis-config.xml 中加載才行。mybatis-cinfig.xml 可以加載多個配置文件,每個配置文件對應數據庫中的一張表
③構建會話工廠:SqlSessionFactory
④創建SqlSession對象。會話工廠創建SqlSession對象,該對象中包含執行sql所有方法。

mybatis-config.xml核心配置文件:

每個mybatis應用都是以一個 SqlSessionFactory 的實例為核心的。SqlSessionFactory的實例通過SqlSessionBuilder獲得。

在maven中配置mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/db_mybatis?serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 引入映射文件 -->
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>

創建db.properties

properties:該標簽可以引入外部配置的屬性,也可以自己配置。該配置標簽所在的同一個配置文件中的其他配置均可引用此配置中的屬性。

我們的配置文件中數據庫連接相關參數其實是寫死的,但是我們清楚一般情況下這種參數的配置我們不會寫死,而是通過properties這種配置文件進行讀取。

db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/db_mybatis?serverTimezone=GMT%2B8
db.username=root
db.password=root

在mybatis-config配置文件中通過properties標簽引入以上配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- properties標簽使用resource屬性引入db.properties配置文件 -->
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 通過${屬性名}獲取具體屬性 -->
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
<!-- 引入映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>

創建mybatis的mapper映射:
數據庫的準備:

tb_user的腳本文件

create database db_mybatis character set utf8;use db_mybatis;create table tb_user(
id int primary key auto_increment,
username varchar(20),
password varchar(20)
);insert into tb_user(username,password) values('tom','123'),('jerry','456');

創建實體類:

public class User {Integer id;String username;String password;public User() {}public User(Integer id, String username, String password) {this.id = id;this.username = username;this.password = password;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +'}';}
}  

創建mapper接口:

mapper接口:命名方式為相關類的實體類(User ---> UserMapper )

Mapper.xml文件:命名方式與對應的Mapper接口保持一致(UserMapper --> UserMapper.xml),位置一般在resource目錄下創建mapper目錄,把所有的mapper.xml保存到這里。

創建mapper接口:
public interface UserMapper {
/**
* 新增用戶數據方法
* @return 新增結果
*/
Integer addUser();
}

創建UserMapper.xml

namespace屬性:此屬性的作用就是綁定當前映射xml文件與對應接口的關系。需要把UserMapper的全限定名填入到namespace屬性中,簡歷接口與xml文件的關系

crud標簽:select,update,insert,delete標簽中的id對應的就是mapper接口中要執行的方法。

<?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">
<mapper namespace="com.java.mapper.UserMapper"><!-- addUser() --><insert id="addUser">insert into tb_user(username,password) values('小明','123')</insert>
</mapper>

在mybatis-config.xml文件里面引入映射文件的位置

<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>

構建會話工廠:

配置好mybatis-config.xml,mapper接口,mapper.xml映射文件之后,現在要通過mybatis提供的API來執行具體的sql語句。

junit單元測試:
Junit是Java語言的單元測試框架。
Junit 測試也是程序員測試,即所謂的白盒測。

一般在項目的 test>java 目錄中編寫測試類型,通過@test注解來聲明測試方法

mybatisAPI的調用:

SqlSessionFactory:生產SqlSession的工廠

工廠SqlSession:通過SqlSessionFactory生產而來,代表Java程序和數據庫之間的會話,通過此對象來完成SQL語句的執行和獲取結果等操作。

 @Testpublic void test(){try {//讀取mybatis-config.xml核心配置文件InputStream is = Resources.getResourceAsStream("mybatis-config.xml");//創建SqlSessionFactory對象SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//openSession方法默認是不會進行自動事務提交的,所以我們如果想做
DML操作并且自動提交事務,需要加上true參數,默認為falseSqlSession sqlSession = sqlSessionFactory.openSession(true);UserMapper mapper = sqlSession.getMapper(UserMapper.class);//測試添加的結果int num= mapper.addUser();System.out.println(num);sqlSession.close();} catch (IOException e) {e.printStackTrace();}}

mybatis-config配置文件的其他配置:

MyBatis 最核心的全局配置文件是 mybatis-config.xml 文件,其中包含了

數據庫的連接配置信息、Mapper 映射文件的加載路徑、全局參數、類型別名等

配置項配置項的解析。。。。
configuration包裹所有配置標簽,是整個配置文件的頂級標簽。
properties該標簽可以引入外部配置的屬性,也可以自己配置
setting全局配置參數,用來配置一些改變運行時行為的信息,例如是否使用緩存機制,是否使用延遲加載,是否使用錯誤處理機制等。
typeAliases類型別名,用來設置一些別名來代替 Java 的長類型聲明
environments設置多個連接數據庫的環境
environment設置具體的連接數據庫的環境信息
transactionManager事務管理,指定 MyBatis 的事務管理器
dataSource數據源,使其中的 type 指定數據源的連接類型,在標簽對中可以使用 property 屬性指定數據庫連接池的其他信息
mappers映射器,配置 sql 映射文件的位置,告知 MyBatis 去哪里加載 sql映射配置

案例演示:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//MyBatis.org//DTD Config 3.0//EN"
"http://MyBatis.org/dtd/MyBatis-3-config.dtd">
<configuration>
<!-- properties標簽使用resource屬性引入db.properties配置文件 -->
<properties resource="db.properties"></properties>
<!--
environments:設置多個連接數據庫的環境
屬性:
default:設置默認使用的環境的id
-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<environments default="development">
<!--
environment:設置具體的連接數據庫的環境信息
屬性:
id:設置環境的唯一標識,可通過environments標簽中的default設置某一
個環境的id,表示默認使用的環境
-->
<environment id="development">
<!--
transactionManager:設置事務管理方式
屬性:
type:設置事務管理方式,type="JDBC|MANAGED"
type="JDBC":設置當前環境的事務管理都必須手動處理
type="MANAGED":設置事務被管理,例如spring中的AOP
-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--設置驅動類的全類名-->
<property name="driver" value="${db.driver}"/>
<!--設置連接數據庫的連接地址-->
<property name="url" value="${db.url}"/>
<!--設置連接數據庫的用戶名-->
<property name="username" value="${db.username}"/>
<!--設置連接數據庫的密碼-->
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<!-- <mapper resource="UserMapper.xml"/> -->
<!--
以包為單位,將包下所有的映射文件引入核心配置文件
注意:
1. 此方式必須保證mapper接口和mapper映射文件必須在相同的包下
2. mapper接口要和mapper映射文件的名字一致
-->
<package name="com.java.mapper"/>
</mappers>
</configuration>

mybatis完成增刪改查:

添加功能:
mapper層接口編寫public interface UserMapper {//添加userint addUser(User user);
} 

mapper.xml文件

 <insert id="addUser">insert into tb_user(username,password) values(#{username},#{password})
</insert>

test進行測試:

  public SqlSession getSqlSession(){InputStream is = null;try {is = Resources.getResourceAsStream("mybatis-config.xml");} catch (IOException e) {e.printStackTrace();}SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sqlSessionFactory.openSession();return sqlSession;}@Testpublic void testAdd(){User user = new User("都是", "121");SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);int num = mapper.addUser(user);sqlSession.commit();System.out.println(num);}

刪除功能:

mapper層編寫:

public interface UserMapper {<delete id="delUserById">delete from tb_user where id = #{id}</delete>
}  

mapper.xml文件:

 <delete id="delUserById">delete from tb_user where id = #{id}</delete>

test進行測試:

@Testpublic void testDel() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);int num = mapper.delUserById(1);System.out.println(num);}

修改功能:

mapper接口:

public interface UserMapper {//修改int updateUser(User user);
}  

mapper.xml文件:

    <update id="updateUser">update tb_user set username = #{username},password = #{password}where id = #{id}</update>

test測試:

@Testpublic void testUpdate() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = new User(1,"孫道嗯","123456");int num = mapper.updateUser(user);sqlSession.commit();System.out.println(num);}

查詢功能:

xml寫法:

注意:

如果利用xml寫法進行查詢,就必須確定以下映射關系才能使用

resultType:設置默認映射關系

resultMap:設置自定義映射關系(多用于復雜查詢-多表查詢)

無參數查詢(查詢全部):

mapper接口:

//查詢全部List<User> getUserList();

mapper.xml文件:

   <select id="getUserList" resultType="org.example.entity.User">select * from tb_user</select>

test測試:

@Testpublic void test(){try {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.getUserList();for (User u:userList) {System.out.println(u);}sqlSession.close();} catch (IOException e) {e.printStackTrace();}}//User{id=1, username='孫道嗯', password='123456'}
User{id=2, username='jerry', password='456'}
User{id=4, username='都是', password='121'}
User{id=7, username='得到', password='111'}
User{id=8, username='是分公司', password='5555'}
User{id=9, username='反打', password='1231'}
User{id=10, username='的發揮', password='131'}
User{id=11, username='發達·', password='5453'}
User{id=12, username='光輻射大概', password='423'}

單個參數查詢:

mapper接口:

   //單個查詢User getUserById(Integer id);

mapper.xml文件:

 <select id="getUserById" resultType="org.example.entity.User">select * from tb_user where id = #{id}</select>

test測試:

   @Testpublic void testGetUserById(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);int user = mapper.delUserById(1);System.out.println(user);}

多個參數查詢:

mapper接口:

//根據username和pwd查詢User getUserByNameAndPwd(@Param("name") String name,@Param("pwd") String pwd);

mapper.xml文件:

 <select id="getUserByNameAndPwd" resultType="org.example.entity.User">select * from tb_user whereusername = #{name}and password = #{pwd}</select>

test測試:

    @Testpublic void testGetByNameAndPwd(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.getUserByNameAndPwd("孫道嗯", "123456");System.out.println(user);}

map參數查詢:

mapper接口:

 //傳遞map類型的參數User getUserByMap(Map<String,Object> map);

mapper.xml文件:

  <select id="getUserByMap" resultType="org.example.entity.User">select * from tb_user whereusername = #{username}and password = #{password}</select>

test測試:

 @Testpublic void testMap(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String,Object> map = new HashMap<>();map.put("username","孫道嗯");map.put("password","123456");User userByMap = mapper.getUserByMap(map);System.out.println(userByMap);}
//User{id=1, username='孫道嗯', password='123456'}

查詢單個數據返回數據為map:

mapper接口:

一條數據對應一個Map,將多個Map放入到一個Map集合中,但是要配合 注解設置Map集

合的鍵,@MapKey注解會把對應查詢出的數據中的某一個字段作為建,所以必須要保證此字段不能重復,所以一般為id。

//查詢單個數據返回數據為map
    @MapKey("id")Map<String,Object> getUserMapByname(String name);

mapper.xml文件:

    <select id="getUserMapByname" resultType="java.util.Map">select * from tb_user where username = #{name}</select>

test測試:

 @Testpublic void testMapByName(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String, Object> map = mapper.getUserMapByname("孫道嗯");System.out.println(map);}
//{1={password=123456, id=1, dept_id=2, username=孫道嗯}}

查詢list的map集合數據:

mapper接口:

//查詢List的map集合@MapKey("id")List<Map<String,User>> mapList();

mapper.xml文件:

   <select id="mapList" resultType="org.example.entity.User">select * from tb_user</select>

test測試:

 @Testpublic void testMapList(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<Map<String, User>> maps = mapper.mapList();Iterator<Map<String, User>> it = maps.iterator();while (it.hasNext()){System.out.println(it.next());}}
//User{id=1, username='孫道嗯', password='123456'}
User{id=2, username='jerry', password='456'}
User{id=4, username='都是', password='121'}
User{id=7, username='得到', password='111'}
User{id=8, username='是分公司', password='5555'}
User{id=9, username='反打', password='1231'}

查詢返回map集合的數據:

mapper接口:

//查詢map集合數據@MapKey("id")Map<String,User>  maps();

mapper.xml文件:

    <select id="maps" resultType="java.util.Map">select * from tb_user</select>

test測試:

 @Testpublic void testMaps(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<Object, User> maps = mapper.maps();System.out.println(maps);}
//{1={password=123456, id=1, dept_id=2, username=孫道嗯}, 2={password=456, id=2, dept_id=2, username=jerry}, 4={password=121, id=4, dept_id=2, username=都是}, 7={password=111, id=7, dept_id=1, username=得到}, 8={password=5555, id=8, dept_id=1, username=是分公司}, 9={password=1231, id=9, dept_id=3, username=反打}, 10={password=131, id=10, dept_id=3, username=的發揮}, 11={password=5453, id=11, dept_id=2, username=發達·}, 12={password=423, id=12, dept_id=2, username=光輻射大概}}

添加時獲取自增主鍵:

mapper接口:

//獲取自增主鍵int getAddUserId(User user);

mapper.xml文件:

    <insert id="getAddUserId" useGeneratedKeys="true" keyProperty="id" >insert into tb_user(username,password) values(#{username},#{password})</insert>

test測試:

  @Testpublic void testAddUserGetId(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = new User("訂單但", "111");int num = mapper.getAddUserId(user);System.out.println(num);System.out.println(user);}
//1
User{id=13, username='訂單但', password='111'}

模糊查詢:

mapper接口:

//模糊查詢List<User> getUserByLike(@Param("username") String username,@Param("password") String password);

mapper.xml文件:

  <sql id="userSql">id,username,password</sql><select id="getUserByLike" resultType="org.example.entity.User">select<include refid="userSql"></include>from tb_user<where><if test="username != null and username != ''">and username like concat('%',#{username},'%')</if><if test="password != null and password != ''">and password like concat('%',#{password},'%')</if></where></select>

test測試:

   @Testpublic void getUserByLike(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> user = mapper.getUserByLike("道", "111");System.out.println(user);}

分頁查詢:

mapper接口:

//分頁查詢List<User> selectUserByLimit(Map<String,Integer> map);

mapper.xml文件:

  <select id="selectUserByLimit" resultType="org.example.entity.User">select * from tb_userlimit #{start},#{pageSize}</select>

test測試:

 @Testpublic void testLimit(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String,Integer> map = new HashMap<>();map.put("start",0);map.put("pageSize",2);List<User> users = mapper.selectUserByLimit(map);for (User u:users) {System.out.println(u);}}
//User{id=1, username='孫道嗯', password='123456'}
User{id=2, username='jerry', password='456'}

mybatis中傳遞參數:

兩種常見的方式:

${} :此種方式本質為字符串拼接
#{} :此種方式為占位字符串
select * from ${tableName} where username = #{username}
獲取單個參數:

mapper接口:

@select(select * from tb_user where id = #{id})
User getUserById(Integer id);

test測試:

 @Testpublic void testAddUserGetId(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user =mapper.getUserById(1);System.out.println(user);}    

獲取多個參數:

需求:查詢tb_user表中id為1的數據。此時需要把id和表明都作為參數

注意:表名不能使用#{},因為表名位置需要進行字符串拼接,#{}占位符會出現語法問題。

示例: select * from ? where id = ?

mapper接口:

@Select("select * from ${table} where id = #{id}")
User selectByIdAndTable(String table,Integer id);

test測試:

 @Testpublic void testAddUserGetId(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user =mapper.selectByIdAndTable("tb_user",1);System.out.println(user);}
//此時會報錯的,找不到參數

方法中給出了兩個參數,在mybatis處理時,參數名稱分別是arg0,arg1.或者使用param1和param2訪問這兩個參數。

mapper接口:

@Select("select * from ${arg0} where id = #{arg1}")
User selectByIdAndTable(String table,Integer id);

或者

@Select("select * from ${param1} where id = #{param2}")
User selectByIdAndTable(String table,Integer id);

最常用的寫法:

@Select("select * from ${table} where id = #{id}")User selectByIdAndTable(@Param("table") String table,@Param("id") Integer id
);

Map參數類型:

mapper接口:

@Select("select * from tb_user where username = #{username} and password = #{password}")
User selectByUsernameAndPassword(Map<String,Object> map);

test測試:

 @Testpublic void testAddUserGetId(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);//手動將輸入放入都Map中Map<String,Object> map = new HashMap<>();map.put("username","jerry");map.put("password","456");User user = userMapper.selectByUsernameAndPassword(map);}

實體參數類型:

mapper接口:

@Insert("insert into tb_user(username,password) values(#{username},#
{password})")
Integer addUser(User user);

test測試:

 @Testpublic void testAddUserGetId(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = new User("河南","111");int num =  mapper.addUser(user);}//1

總結:mybatis執行的時候,會自動讀取參數user的屬性填充到對應的占位符號#{},例如讀取到User中的usernaem屬性,填充到#{username}。

mybatis獲取參數方式詳解:

使用${}格式的占位符時,可以表示SQL語句中的任何部分,可以是某個值,也可以是SQL語句中的某個片段!使用這種占位符時,MyBatis在處理過程中,是先將占位符對應的值拼接到SQL語句中,然后,將整個SQL語句交給數據進行詞法分析、語義分析、編譯,如果無誤,就可以直接執行SQL語句,如果出現語法錯誤,就會導致程序運行過程中出現異常!

使用#{}格式的占位符時,由于使用了預編譯的做法,所以,這種處理方式是安全的,而${}占位符是先拼接SQL語句再執行的過程,并沒有預編譯的處理,所以,存在SQL注入的風險的!

mybatis關聯查詢:

數據準備:
CREATE TABLE tb_dept (
id INT(11) AUTO_INCREMENT COMMENT '部門ID',
name VARCHAR(20) NOT NULL COMMENT '部門名',
PRIMARY KEY (id)
);
-- 在tb_dept表中插入數據
INSERT INTO tb_dept (name) VALUES ('Java'), ('C++'), ('Linux');
-- tb_user 表中增加外鍵列,dept_id
ALTER TABLE tb_user ADD COLUMN dept_id INT;
-- 根據 tb_dept 中id更新tb_user表中dept_id列的值,供測試使用
UPDATE tb_user u SET dept_id = (SELECT d.id FROM tb_dept d WHERE
name='Java') WHERE u.id >5;
UPDATE tb_user u SET dept_id = (SELECT d.id FROM tb_dept d WHERE
name='C++') WHERE u.id <=5;

創建vo類型:

entitty.UserVo

public class UserVO {Integer id;
String username;
String name;
}  

mapper接口:

@Select("select u.id,u.username,d.name from tb_user u left join tb_dept d \n" +
"on u.dept_id=d.id;")
List<UserVO> findUserDept();

mapper.xml文件:

<!-- List<UserVO> findUserDept(); -->
<select id="findUserDept" resultType="vo.UserVO">
select u.id,u.username,d.name
from tb_user u
left join tb_dept d
on u.dept_id=d.id;
</select>

test測試:

@Test
public void findUserDeptTest(){try {SqlSession sqlSession = getSqlSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);List<UserVO> list = userMapper.findUserDept();list.forEach(user -> System.out.println(user));} catch (IOException e) {e.printStackTrace();}
}

resultMap的應用:

需要執行的sql

select d.*,u.id,u.username from tb_dept d
left join tb_user u on d.id = u.dept_id
where d.id=1;

DeptVo

public class DeptVo {Integer id;
String name;
List<User> users;
} 

mapper接口:

/**
* 查詢當前部門信息,包括此部門對應的用戶信息
* @param id 部門編號
* @return 部門信息+部門員工信息
*/
DeptVo findDept(Integer id);

resultMap屬性:設置自定義映射id名稱

resultMap標簽:

id 表示自定義映射的唯一標識,不能重復
type 查詢的數據要映射的實體類的類型id標簽:設置主鍵字段映射result標簽 設置普通字段映射column 映射具體列(數據庫中的字段)property 具體映射屬性(實體類中的屬性)collection:property 具體映射的屬性oftype 映射類型

mapper.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.xml與對應那個Mapper接口的關系,要求
接口名稱為:全限定名 -->
<mapper namespace="mapper.DeptMapper">
<resultMap id="deptMap" type="vo.DeptVo"><id column="id" property="id"></id><result column="name" property="name"></result><collection property="users" ofType="entity.User"><result column="id" property="id"></id><result column="username" property="username"></result><result column="password" property="password"></result></collection>
</resultMap>
<!-- DeptVo findDept(Integer id) --><select id="findDept" resultMap="deptMap">select d.id,name,u.id,username,password fromtb_dept dleft join tb_user u ond.id = u.dept_id where d.id=#{id};</select>
</mapper>

test測試:

@Test
public void findDeptTest(){try {SqlSession sqlSession = MyBatisDemo.getSqlSession();DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);DeptVo vo = deptMapper.findVoById(1);System.out.println(vo);} catch (IOException e) {e.printStackTrace();}
}

說明:字段名和實體類中的屬性名不一致,但是字段名符合數據庫的規則(使用了_),實體類中的屬性名符合java規則(使用了駝峰命名法)。可以通過三種方式處理字段名和實體類中的屬性映射關系。

起別名:
select * from d_name dName from dept
@Results注解:
//column 數據庫的字段,property 實體類的屬性@Results({@Result(column = "create_time",property = "createTime"),  @Result(column = "update_time",property = "updateTime")})@Select("select id,name,create_time createTime,update_time updateTime from dept")public List<Dept> selectAll();
開啟字段名轉換為駝峰:
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

mybatis中加入log4j查看日志:

添加依賴
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

添加配置:

在resource目錄中添加即可:

log4j.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd
HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
日志的級別:FATAL(致命)>ERROR(錯誤)>WARN(警告)>INFO(信息)>DEBUG(調試)

定義SQL片段:

簡介:
mybatis的<sql> 標簽一般是用來封裝sql語句、或者復用語句的,然后用<include>標簽來調用
創建sql片段示例:
<sql id="selectSql">select * from tb_user
</sql>
調用sql片段:
<select id="getUserList" resultType="User"><include refid="selectSql"></include>
</select><sql id="if_sql"><if test="id != null and id != ''">and id = #{id}</if><if test="username != null and username != ''">and username = #{username}</if>
</sql>

調用:

  <select id="selectByWhere" resultType="org.example.entity.User">select * from tb_user<where><include refid="if_sql"></include></where></select>

mybatis的動態SQL:

動態SQL技術是一種根據特定條件動態拼裝SQL語句的功能,它存在的意義是為了

解決拼接SQL語句字符串時的問題

簡單理解:

根據調用方法時給出的參數不同,最終生成的SQL語句會不同

動態SQL-if:

if 一般實現的效果就是根據不同的參數,查詢出不同的結果。

<if test=" "></if>

當test條件表達式里面的值,為true時,才會拼接執行

mapper接口:

List<User> getUserByIf(Map map);

mapper.xml文件:

<!-- selectDynamicIf -->
<select id="getUserByIf" resultType="entity.User">
<!-- 1=1保證語句在沒有條件時不會多出where子句報錯,where 1=1保證語句的
正確性 -->
select * from tb_user where 1=1<if test="id != null and id != ''">and id=#{id}</if><if test="username != null and username != ''">and username = #{username}</if>
</select>

test測試:

@Test
public void findUserDeptTest(){try {SqlSession sqlSession = getSqlSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);Map map = new hashMap();map.put("username","孫道嗯");mpa.put("password","111");} catch (IOException e) {e.printStackTrace();}
}

動態sql-where:

上面執行的sql語句中 where1=1,有點多余。where可不可以變成動態的??

加入<where>標簽即可

mapper.xml文件:

<mapper namespace="mapper.DynamicMapper"><!-- getuserByWhere --><select id="getuserByWhere" resultType="entity.User">select * from tb_user<where><if test="id != null and id != ''">and id=#{id}</if><if test="username != null and username != ''">and username = #{username}</if></where></select>
</mapper>

但是我們修改sql語句為and或者or放在后面,程序就會報錯。

<mapper namespace="mapper.DynamicMapper"><!-- getUserByWhere --><select id="getUserByWhere" resultType="entity.User">select * from tb_user<where><if test="id != null and id != ''">id=#{id} and</if><if test="username != null and username != ''">username = #{username}</if></where></select>
</mapper>

當只有第一條數據時,就會報錯,因為后面多了一個and關鍵字。

select * from tb_suer where id = ? and

動態SQL-trim:

trim用于去掉標簽或添加標簽內容

常用屬性:

prefix:在trim標簽中的內容的前面添加耨寫內容suffix:在trim標簽中的內容的后面添加某些內容prefixOverrides:在trim標簽中的內容的前面去掉某些內容suffixOverrides:在trim標簽中的內容的后面去掉某些內容

mapper.xml文件:

<select id="getUsrByTrim" resultType="entity.User">
select * from tb_user
<!-- prefix在執行判斷前添加where suffixOverrides判斷后去掉and,如果還
有or可以通過 and|or的方式來表示多個關鍵字 --><trim prefix="where" suffixOverrides="and"><if test="id != null and id != ''">id=#{id} and</if><if test="username != null and username != ''">username = #{username}</if></trim>
</select>

動態SQL-choose,when,otnerwise:

choose:表示此套標簽的最外層 類似于 switch

when:表示判斷各種條件,類似于case

otherwise:所有條件都不符合時走這里 類似于default

mapper.xml文件:

<select id="getUserByChoose" resultType="entity.User">select * from tb_user<where><choose><when test="id != null and id != ''">id=#{id}</when><when test="username != null and username != ''">username = #{username}</when><otherwise>password = 123</otherwise></choose></where>
</select>

test測試:

@Test
public void findUserDeptTest(){try {SqlSession sqlSession = getSqlSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);Map map = new HashMap();map.put("id",1);map.put("username","孫道嗯");List<User> userList = userMapper.getUserByChoose(map);system.out.println(userList);} catch (IOException e) {e.printStackTrace();}
}

動態SQL-set:

<set> :動態的在SQL語句中插入set關鍵字,并會刪掉額外的逗號。(用于update語句中)

mapper接口:

 //修改用戶信息Integer updateUserBySet(User user);

mapper.xml文件:

    <update id="updateUserBySet">update tb_user<set><if test="username != null and username != ''">username = #{username},</if><if test="password != null and password != ''">password = #{password}</if></set>where id = #{id}</update>

test測試:

   @Testpublic void updateUserBySet(){SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = new User(1,"但是","3333");Integer num = mapper.updateUserBySet(user);System.out.println(num);}

動態SQL-foreach:

動態SQL一個常見使用場景,是對集合遍歷。

mapper接口:

Integer delUserByIds(@Param("ids")Integer[] ids);

不加當前傳遞的是數字格式就需要在collection屬性上添加 array 如果是List集合

就需要添加 list 屬性值

屬性解釋:

collection:表示被遍歷的對象。如果沒有添加@Param注解時,參數的類型時list集合類型,則取值為list。如果參數類型為數組,則取值為array,否則取值就是@Param注解中配置的名稱。

item:將根據這個屬性配置的值來使用數據

separator:分隔符,用于分隔遍歷時生成的多個占位符

oppen和close:遍歷生成的SQL語句片段的起始字符串和結束字符串。比如:open="(" close=")"

動態刪除案例:

mapper.xml文件:

<!-- Integer delUserByIds(Integer[] ids); -->
<delete id="delUserByIds">DELETE FROM tb_user WHERE id IN<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach>
</delete>

test測試:

@Test
public void findUserDeptTest(){try {SqlSession sqlSession = getSqlSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);Integer num = userMapper.delUserByIds(new Integer[]{1,2,3});system.out.println(num);} catch (IOException e) {e.printStackTrace();}
}

mybatis的緩存:

什么是緩存?
存在內存中的臨時數據
將用戶經常查詢的數據放入緩存(內存)中,用戶去查詢數據就不需要每次都從磁盤上查
詢,從緩存(內存)中查詢,從而提高查詢效率,解決了高并發系統的性能問題
為什么使用緩存?
減少和數據庫的交互次數,減少系統開銷,提高系統效率。
什么樣的數據需要緩存?
經常查詢并且不經常改變的數據

mybatis提供的緩存:

mybatis系統中默認定義了兩級緩存:一級緩存,二級緩存

①默認情況下,MyBatis默認開啟一級緩存(SqlSession級別的緩存,也稱之為本地緩
存,SqlSession對象使用到close)②二級緩存需要手動開啟和配置,它是基于SqlSessionFactory級別的緩存(簡單理解就
是通過同一個SqlSessionFactory創建的SqlSession查詢的結果會被緩存)

一級緩存:

一級緩存稱為本地緩存,只在SqlSession這個區間有效。

一級緩存相當于一個map

與數據庫同一會話期間查詢到的數據會放入到本地緩存中。

以后需要獲取相同的數據,直接從緩存中拿,不需要再次查找數據庫。

mapper接口:

User getUserById(Integer id);

mapper.xml文件:

<select id resultType="User">select * from tb_user where id = #{id}
</select>

test測試:

public void getUserById(){try {SqlSession sqlSession = getSqlSession();//一級緩存CacheMapper cacheMapper = sqlSession.getMapper(CacheMapper.class);User user = cacheMapper.getUserById(2);System.out.println(user);System.out.println("-------------------------------------------");User user1 = cacheMapper.selectById(2);System.out.println(user1);//結果為true,證明user與user1引用地址都相同,從緩存中讀取的數據System.out.println(user==user1);//一級緩存結束sqlSession.close();} catch (IOException e) {e.printStackTrace();}
}

一級緩存失效的情況:
1,不同的SqlSession對應不同的一級緩存
2,同一個SqlSession但是查詢條件不同

test測試:

@Test
public void getUserById(){try {SqlSession sqlSession = getSqlSession();//一級緩存CacheMapper cacheMapper = sqlSession.getMapper(CacheMapper.class);User user = cacheMapper.getUserById(2);System.out.println(user);System.out.println("-------------------------------------");User user1 = cacheMapper.selectById(5);//查詢條件不同System.out.println(user1);//結果為true,證明user與user1引用地址都相同,從緩存中讀取的數據System.out.println(user==user1);//一級緩存結束sqlSession.close();} catch (IOException e) {e.printStackTrace();}
}

3,同一個SqlSession兩次查詢期間執行了任何一次增刪改操作

mapper接口:

//根據id查詢
@Select("select * from tb_user where id = #{id}")
User getUserById(Integer id);//修改信息
@Update("update tb_user set username = #{username} where id = #{id}")
Integer UpdateById(
@Param("id") Integer id,
@Param("username") String username
);

test測試:

@Test
public void getUserById(){try {SqlSession sqlSession = getSqlSession();//一級緩存CacheMapper cacheMapper = sqlSession.getMapper(CacheMapper.class);User user = cacheMapper.getUserById(2);System.out.println(user);Integer num = cacheMapper.UpdateById(2,"tom");System.out.println(num);System.out.println("------------------------------------");User user1 = cacheMapper.getUserById(5);System.out.println(user1);//結果為true,證明user與user1引用地址都相同,從緩存中讀取的數據System.out.println(user==user1);//一級緩存結束sqlSession.close();} catch (IOException e) {e.printStackTrace();}
} 

4,同一個SqlSession兩次查詢期間手動清空了緩存

test測試:

@Test
public void getUserById(){try {SqlSession sqlSession = getSqlSession();//一級緩存CacheMapper cacheMapper = sqlSession.getMapper(CacheMapper.class);User user = cacheMapper.getUserById(2);System.out.println(user);//手動調用清理緩存方法sqlSession.clearCache();System.out.println("-----------------------------------------");User user1 = cacheMapper.getUserById(2);System.out.println(user1);//結果為true,證明user與user1引用地址都相同,從緩存中讀取的數據System.out.println(user==user1);//一級緩存結束sqlSession.close();} catch (IOException e) {e.printStackTrace();}
}

二級緩存:
  • 二級緩存也稱之為全局緩存,因為一級的作用域太低了,所以才有了二級緩存

  • 二級緩存基于SqlSessionFactory級別的緩存,通過同一個SqlSessionFactory創建的SqlSession查詢的結果會被緩存
工作機制:
①一個SqlSession查詢一條數據,這個數據就會被放在當前SqlSession的一級緩存中②如果當前SqlSession關閉了,這個SqlSession對應的一級緩存就沒了,但我們的需求是
SqlSession關閉,一級緩存中的數據被保存在二級緩存中③新的SqlSession查詢相同信息,就可以從二級緩存中獲取內容

開啟二級緩存:

mapper.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">
<mapper namespace="com.java.mapper.UserMapper"><cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
</mapper>

解讀:

創建了一個Fifo緩存,每個60秒刷新,最多可以存儲結果對象或列表512個引用。返回的對象被認為是只讀的,

可用的清楚策略:
LRU – 最近最少使用:移除最長時間不被使用的對象。
FIFO – 先進先出:按對象進入緩存的順序來移除它們。
SOFT – 軟引用:基于垃圾回收器狀態和軟引用規則移除對象。
WEAK – 弱引用:更積極地基于垃圾收集器狀態和弱引用規則移除對象。

默認的是 LRU

使用二級緩存:
1,實體類必須實例化
2,必須使用mapper.xml映射
3,因為二級緩存是基于SqlSessionFactory的,SqlSession對象要在同一個緩存范圍內

新創建一個CacheMapper.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">
<mapper namespace="mapper.CacheMapper"><cacheeviction="FIFO"flushInterval="60000"size="512"readOnly="true"/><!-- User selectById(Integer id); --><select id="selectById" resultType="entity.User">select * from tb_user where id=#{id}</select>
</mapper>

test測試:

@Test
public void selectByIdTest(){try {//獲取同一個SqlSessionFactory下的SqlSession會話對象SqlSessionFactory sqlSessionFactory =MyBatisDemo2.getSqlSessionFactory();//開啟2個會話 sqlSession1開啟SqlSession sqlSession1 = sqlSessionFactory.openSession(true);SqlSession sqlSession2 = sqlSessionFactory.openSession(true);//一級緩存CacheMapper cacheMapper =sqlSession1.getMapper(CacheMapper.class);User user = cacheMapper.selectById(2);System.out.println(user);//一級緩存結束 sqlSession1會話結束sqlSession1.close();System.out.println("---------------------------------------");CacheMapper cacheMapper1 =sqlSession2.getMapper(CacheMapper.class);User user1 = cacheMapper1.selectById(2);System.out.println(user1);//結果為true,證明user與user1引用地址都相同,從緩存中讀取的數據System.out.println(user==user1);//一級緩存結束 sqlSession2會話結束sqlSession2.close();} catch (IOException e) {e.printStackTrace();}
}

結論:

1. 一級緩存默認開啟:用戶訪問進來先查看一級緩存是否有查詢的數據,沒有在走數據庫查詢
2. 當二級緩存開啟以后:用戶訪問進來先查看二級緩存是否有查詢的數據,沒有在走一級緩
存,如果都沒有在走數據庫查詢

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/211140.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/211140.shtml
英文地址,請注明出處:http://en.pswp.cn/news/211140.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaScript中的發布訂閱和觀察者模式:如何優雅地處理事件和數據更新

?&#x1f308;個人主頁&#xff1a;前端青山 &#x1f525;系列專欄&#xff1a;JavaScript篇 &#x1f516;人終將被年少不可得之物困其一生 依舊青山,本期給大家帶來JavaScript篇專欄內容:JavaScript-訂閱觀察者模式 目錄 說說你對發布訂閱、觀察者模式的理解&#xff1f;…

用生命做事,無人能超越

今天看了《藝術人生——紅樓夢劇組20年再聚首》&#xff0c;然后搜索了一下里面的核心人物及其經歷。實話說&#xff0c;看完后我內心無法平靜&#xff0c;涌動著各種思緒。一是20多年前這群青澀演員的人生際遇&#xff0c;讓我感慨。很多人&#xff0c;用這樣的機會&#xff0…

‘ChatGLMTokenizer‘ object has no attribute ‘tokenizer‘解決方案

大家好,我是愛編程的喵喵。雙985碩士畢業,現擔任全棧工程師一職,熱衷于將數據思維應用到工作與生活中。從事機器學習以及相關的前后端開發工作。曾在阿里云、科大訊飛、CCF等比賽獲得多次Top名次。現為CSDN博客專家、人工智能領域優質創作者。喜歡通過博客創作的方式對所學的…

Linux系統---簡易伙伴系統

顧得泉&#xff1a;個人主頁 個人專欄&#xff1a;《Linux操作系統》 《C/C》 《LeedCode刷題》 鍵盤敲爛&#xff0c;年薪百萬&#xff01; 一、題目要求 1.采用C語言實現 2.伙伴系統采用free_area[11]數組來組織。要求伙伴內存最小為一個頁面&#xff0c;頁面大小為4KB…

我在Vscode學OpenCV 圖像處理二(濾除噪聲干擾)

圖像處理二 濾除噪聲干擾三、噪聲3.1圖像噪聲3.2 濾波3.2.1均值濾波&#xff08;1&#xff09;錨點&#xff08;2&#xff09;中心點&#xff08;下面第3小點會詳細解釋&#xff09;&#xff08;3&#xff09;核的大小奇偶數的區別&#xff08;1&#xff09;舉例奇偶的例子&…

【工具使用-JFlash】如何使用Jflash擦除和讀取MCU內部指定扇區的數據

一&#xff0c;簡介 在調試的過程中&#xff0c;特別是在調試向MCU內部flash寫數據的時候&#xff0c;我們常常要擦除數據區的內容&#xff0c;而不想擦除程序取。那這種情況就需要擦除指定的扇區數據即可。本文介紹一種方法&#xff0c;可以擦除MCU內部Flash中指定扇區的數據…

六級高頻詞匯1

目錄 高頻詞匯 參考連接 高頻詞匯 1. alter v. 改變&#xff0c;改動&#xff0c;變更 2. burst vi. n. 突然發生&#xff0c;爆裂 3. dispose vi. 除掉&#xff1b;處置&#xff1b;解決&#xff1b;處理(of) 4. blast n. 爆炸&#xff1b;氣流 vi. 炸&#xff0c;炸掉 …

【win10用vim開發stm32】二、vimspector的單片機調試

▲ 我的vim配置倉庫: gitee&#xff0c;vim相關優先在gitee更新&#xff0c;博客vim專欄作為部分補充和使用說明 ▲ 本文提供vimspector調試的一個示例&#xff0c;和keil的調試功能比當然還是有很大差距&#xff0c;不過簡單的調試功能如單步、復位、運行這些都跑通了&#xf…

Unity打包到Webgl平臺以及遇到的問題

Unity打包到Webgl平臺以及遇到的問題 參考網站 Unity打包WebGL的全過程及在打包和使用過程中會遇到的問題(本地測試)-CSDN博客 unity打包到Webgl 并配置能正常運行 這里我用的是Unity2022.3.3f1c1版本 有兩種方法 1、配置本地web服務 2、安裝vsCode>添加插件LiveServe…

AI仿寫軟件大全,當然熱門的仿寫軟件

在創作過程中&#xff0c;往往需要大量的靈感和原創性&#xff0c;而AI仿寫軟件便提供了一種高效、智能的解決方案。本文旨在專心分享AI仿寫軟件有哪些&#xff0c;并為大家解析哪幾款好用的AI仿寫軟件。 AI仿寫的使用 隨著互聯網的快速發展&#xff0c;內容創作需求不斷增長&…

Rellax.js,一款超酷的 JavaScript 滾動效果庫

嗨&#xff0c;大家好&#xff0c;歡迎來到猿鎮&#xff0c;我是鎮長&#xff0c;lee。 又到了和大家見面的時間&#xff0c;今天和大家分享一款輕松實現視差滾動效果的 JavaScript 庫——Rellax.js。無需大量的配置&#xff0c;即可為你的網站增色不少。 什么是Rellax.js&am…

奧威亞教學視頻應用云平臺 VideoCover任意文件上傳漏洞復現

0x01 產品簡介 廣州市奧威亞電子科技有限公司教學視頻應用云平臺是一個專門為教育機構和個人教師設計的在線學習平臺。該平臺提供豐富的教學資源和功能,旨在提升教學效果和學習體驗。 0x02 漏洞概述 奧威亞教學視頻應用云平臺 VideoCover.aspx接口處存在任意文件上傳漏洞,未…

數字邏輯電路基礎-組合邏輯電路之4位先行進位加法器

文章目錄 一、問題描述二、verilog源碼三、仿真結果一、問題描述 前面介紹4位行波進位全加器(串行加法器)的原理及verilog實現,但是它是一種串行加法器,當位數多時,比如32位的二進制數相加,由于進位逐位從低位向高位傳遞,這會造成相當大的延遲。對于需要快速加法運算的…

shell基本知識

Linux 系統中 shell 的基本知識 1 什么是 shell Shell 是一種命令行解釋器&#xff0c;它為用戶提供了一個向 Linux 內核發送請求以便運行程序的界面系統級程序。用戶可以用 shell 來啟動、掛起、停止甚至是編寫一些程序。 2 Linux 啟動過程 Linux 系統的啟動過程可以概括為…

tomcat篇---第四篇

系列文章目錄 文章目錄 系列文章目錄前言一、為什么我們將tomcat稱為Web容器或者Servlet容器 ?二、tomcat是如何處理Http請求流程的?三、tomcat結構目錄有哪些?前言 前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到網站,這…

【深度挖掘Java性能調優】「底層技術原理體系」深入挖掘和分析如何提升服務的性能以及執行效率(性能三大定律)

深入挖掘和分析如何提升服務的性能以及執行效率 前提介紹知識要點 性能概述教你看懂程序的性能案例介紹性能指標性能的參考指標性能瓶頸&#xff08;木桶原理&#xff09; 性能分析三大定律Amdahl定律計算公式參數解釋案例分析定律總結 Gustafson定律與Amdahl定律相對立Gustafs…

有理函數的積分

1.多項式相除法&#xff1a; 2.分子分母次數帶來的解題思路差異&#xff1a; 1.總體目的&#xff1a;降次 2.分子次數高于分母&#xff0c;采用多項式相除 3.分子次數等于分母&#xff0c;分離常數 4.最終形式&#xff1a;分子次數低分母次數高 3.不同形式的計算方法 4.按類拆…

51單片機數碼管的使用

IO的使用2–數碼管 本文主要涉及51單片機的數碼管的使用 文章目錄 IO的使用2--數碼管一、數碼管的定義與類型1.1 數碼管的原理圖二、 舉個栗子2.1 一個數碼管的底層函數2.2 調用上面的底層函數顯示具體數字 一、數碼管的定義與類型 數碼管是一種用于數字顯示的電子元件&#x…

[強網擬態決賽 2023] Crypto

文章目錄 Bad_rsaClasslcal Bad_rsa 題目描述&#xff1a; from Crypto.Util.number import *f open(flag.txt,rb) m bytes_to_long(f.readline().strip())p getPrime(512) q getPrime(512) e getPrime(8) n p*q phi (p-1)*(q-1) d inverse(e,phi) leak d & ((1…

mysql select count 非常慢

MySQL select count 性能分析 問題&#xff1a;mysql 在count時發現非常慢 select count(*) from xxx; 無論執行多少次&#xff0c;查詢速度基本穩定在10-12秒之間 環境說明 windows11 x64SSD硬盤MySQL8.0.35數據庫引擎為InnoDB數據行數不到3萬行&#xff0c;但是數據量將近…