一篇文章带你了解并使用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;
    }
    @Override
    public 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语句的执行和获取结果等操作。

 @Test
    public void test(){
        try {
            //读取mybatis-config.xml核心配置文件
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            //创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //openSession方法默认是不会进行自动事务提交的,所以我们如果想做
DML操作并且自动提交事务,需要加上true参数,默认为false
            SqlSession 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 {
    //添加user
    int 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;
    }

@Test
    public 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进行测试:

@Test
    public 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测试:

@Test
    public 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测试:

@Test
    public 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测试:

   @Test
    public 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 where
        username = #{name}
        and password = #{pwd}
    </select>

test测试:

    @Test
    public 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 where
         username = #{username}
        and password = #{password}
    </select>

test测试:

 @Test
    public 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测试:

 @Test
    public 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测试:

 @Test
    public 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测试:

 @Test
    public 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测试:

  @Test
    public 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测试:

   @Test
    public 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_user
        limit #{start},#{pageSize}
    </select>

test测试:

 @Test
    public 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测试:

 @Test
    public 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测试:

 @Test
    public 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测试:

 @Test
    public 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测试:

 @Test
    public 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 from
        tb_dept dleft join tb_user u on
        d.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测试:

   @Test
    public 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">
    <cache
    eviction="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. 当二级缓存开启以后:用户访问进来先查看二级缓存是否有查询的数据,没有在走一级缓
存,如果都没有在走数据库查询

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/233034.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习之全面了解预训练模型

在本专栏中&#xff0c;我们将讨论预训练模型。有很多模型可供选择&#xff0c;因此也有很多考虑事项。 这次的专栏与以往稍有不同。我要回答的问题全部源于 MathWorks 社区论坛&#xff08;ww2.mathworks.cn/matlabcentral/&#xff09;的问题。我会首先总结 MATLAB Answers …

Python time模块详解

time 模块主要包含各种提供日期、时间功能的类和函数。该模块既提供了把日期、时间格式化为字符串的功能&#xff0c;也提供了从字符串恢复日期、时间的功能。 在 Python 的交互式解释器中先导入 time 模块&#xff0c;然后输入 [e for e in dir(time) if not e.startswith(_)…

【数据结构】万字一文手把手解读哈希————(开/闭散列)解决哈希冲突完整详解(6)

前言 大家好吖&#xff0c;欢迎来到 YY 滴 数据结构 系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴 数据结构 专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.哈希&#xff08…

【智能家居】七、人脸识别 翔云平台编程使用(编译openSSL支持libcurl的https访问、安装SSL依赖库openSSL)

一、翔云 人工智能开放平台 API文档开发示例下载 二、编译openSSL支持libcurl的https访问 安装SSL依赖库openSSL(使用工具wget)libcurl库重新配置&#xff0c;编译&#xff0c;安装运行&#xff08;运行需添加动态库为环境变量&#xff09; 三、编程实现人脸识别 四、Base6…

距离度量(各距离含义)

欧氏距离 在n维空间中两点的真实距离&#xff0c;向量的自然长度 由于欧几里得几何学的关系称为欧氏距离 二维空间两点计算公式&#xff1a; d ( x 1 − x 2 ) 2 ( y 1 − y 2 ) 2 d \sqrt{(x_1 - x_2)^2 (y_1 - y_2)^2} d(x1​−x2​)2(y1​−y2​)2 ​ 三维空间两点计算…

fl studio2024试用版本如何汉化中文?

fl studio2024全称Fruity Loops Studio2024&#xff0c;这款软件也被人们亲切的称之为水果&#xff0c;它是一款功能强大的音乐创作编辑软件&#xff0c;拥有全功能的录音室&#xff0c;大混音盘以及先进的音乐制作工具&#xff0c;用户通过使用该软件&#xff0c;就可以轻松制…

springboot mybatis手动事务

创建springboot项目 搭建最简单的SpringBoot项目-CSDN博客 引入mybatis和数据库依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><…

树莓派CSI摄像头在新系统(23年12月)中的不用设置了,没有开关,也没有raspistill

网上都是老信息&#xff0c;用的raspistill命令&#xff0c;至少新系统没有这个东西了&#xff0c;也不会在sudo raspi-config里面也没有摄像头的开关了。 ls /dev/video* 能看到摄像头video0&#xff0c;但是vcgencmd get_camera supported0&#xff0c; detected0&#xff0…

排序算法之四:直接选择排序

1.基本思想 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 2.直接选择排序 在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素 若它不是这组元素中的…

数字系统设计(EDA)实验报告【出租车计价器】

一、问题描述 题目九&#xff1a;出租车计价器设计&#xff08;平台实现&#xff09;★★ 完成简易出租车计价器设计&#xff0c;选做停车等待计价功能。 1、基本功能&#xff1a; &#xff08;1&#xff09;起步8元/3km&#xff0c;此后2元/km&#xff1b; &#xff08;2…

【工厂方法】设计模式项目实践

前言 以采集数据处理逻辑为例&#xff0c;数据采集分为不同种类如&#xff1a;MQTT、MODBUS、HTTP等&#xff0c;不同的采集数据有不同的解析处理逻辑。但总体解析处理步骤是固定的。可以使用工厂方法设计模式简化代码&#xff0c;让代码变得更加优雅。 代码实践 抽象类 总体…

蒙特霍尔问题(选择三扇门后的车与羊)及其贝叶斯定理数学解释

1. 蒙特霍尔问题 有一个美国电视游戏节目叫做“Let’s Make a Deal”&#xff0c;游戏中参赛者将面对3扇关闭的门&#xff0c;其中一扇门背后有一辆汽车&#xff0c;另外两扇门后是山羊&#xff0c;参赛者如果能猜中哪一扇门后是汽车&#xff0c;就可以得到它。 通常&#xf…

工业4.0分类:数字化转型的多维度

引言 工业4.0代表着制造业的数字化革命&#xff0c;它将制造过程带入了数字时代。然而&#xff0c;工业4.0并不是一个单一的概念&#xff0c;而是一个多维度的范畴&#xff0c;包括不同的技术、应用领域、企业规模和实施方式。但在这一多维度的概念中&#xff0c;低代码技术正…

shell基本知识

Linux 系统中 shell 的基本知识 1 什么是 shell Shell 是一种命令行解释器&#xff0c;它为用户提供了一个向 Linux 内核发送请求以便运行程序的界面系统级程序。用户可以用 shell 来启动、挂起、停止甚至是编写一些程序。 2 Linux 启动过程 Linux 系统的启动过程可以概括为…

[强网拟态决赛 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…

L1-032:Left-pad

题目描述 根据新浪微博上的消息&#xff0c;有一位开发者不满NPM&#xff08;Node Package Manager&#xff09;的做法&#xff0c;收回了自己的开源代码&#xff0c;其中包括一个叫left-pad的模块&#xff0c;就是这个模块把javascript里面的React/Babel干瘫痪了。这是个什么样…

【11】Qt Designer

目录 VSCode添加外部工具 QtDesigner PyUIC PyRCC 加载UI文件模板代码 QMainWindow QWidget 常用知识点 1. 修改标题图标 2. 图片资源管理 3. 图片按钮 4. 加载对话框 5. 动态加载Widget 6. 修改主题 其他注意事项 事件被多次触发 PyQt5提供了一个可视化图形工…

【springboot设计源码】庆阳非物质文化遗产展示平台课题背景、目的、意义、研究方法

该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等学习内容。 目录 一、项目介绍&#xff1a; 二、文档学习资料&#xff1a; 三、模块截图&#xff1a; 四、开发技术与运行环境&#xff1a; 五、代码展示&#xff1a; 六、数据库表截图&#xff1…

正在快速兴起的云数据架构

云数据架构的日益流行表明了一个主题&#xff1a;在未来几年&#xff0c;越来越多的企业将把他们的数据中心业务完全迁移到云平台上&#xff0c;因为内部部署数据中心设施具有一些固有的优势。数字时代的企业生存已经成为向云迁移的代名词。 云数据架构的日益流行表明了一个主…