当前位置: 首页 > news >正文

后端:MyBatis

文章目录

  • 1. MyBatis
    • 1-1. Mybatis 工具类的封装
    • 1-2. Mybatis 通过集合或实体类传递参数-实现插入数据(增)
    • 1-3. MyBatis 实现删除数据(删)
    • 1-4. MyBatis 实现修改数据(改)
    • 1-5. MyBatis 实现查询数据(查)
  • 2. MyBatis 配置文件中的一些标签和属性
    • 2-1.environments标签
    • 2-2. dataSource标签
    • 2-3. properties标签
  • 3. MyBatis 面向接口进行CRUD & 小技巧
    • 3-1. mapper.xml 中 ${}和#{}的区别
    • 3-2. mapper.xml 实现模糊查询
    • 3-3. mybatis-config.xml起别名 mapper.xml使用别名
    • 3-4. mybatis-config.xml 配置mapper映射文件
    • 3-5. 在IDEA中创建mybatis配置文件和mapper映射文件模板
    • 3-6. mybatis 获取插入成功之后的主键id
  • 4.MyBatis 参数处理 & 查询专题
    • 4-1. mapper.xml映射文件之多参数
    • 4-2. MyBatis 查询结果之Map,List\<Map\>,Map\<Map\<String,Object\>\>
    • 4-3. MyBatis 查询之结果集映射
  • 5. 动态SQL
    • 5-1. 动态SQL-if标签、where标签、trim标签
    • 5-2. 动态SQL-set标签
    • 5-3. 动态SQL-choose、when、otherwise标签
    • 5-4. 动态SQL-foreach标签
    • 5-5. 动态SQL-sql、include标签
  • 6. MyBatis 之高级映射(一对一,一对多)
    • 6-1. 一对一映射-一个学生只能属于一个班级
    • 6-2. 一对多映射-一个班级拥有多个学生
    • 6-2. 一对多映射-分步查询
  • 7. MyBatis 逆向工程 generatorConfig.xml
  • 8. MyBatis 分页插件 PageHelper
  • 9. MyBatis 注解式开发

1. MyBatis

MyBatis也就是对于jdbc的加强,其实也就是对于后者的一些封装,提高程序开发效率
在这里插入图片描述
MyBatis 依赖和MySQL依赖如下:

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.9</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency>

然后需要写一个mybatis的配置文件,在这个配置文件,需要做到的基本配置有对应数据库的连接信息,比如driver、url、username、password,另外,在这配置文件中,可以注册对应mapper xml映射文件路径。
MyBatis配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><typeAliases><!-- 为 java 类型设置别名 --><typeAlias alias="User" type="com.lz.entity.User"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mytest1?characterEncoding=utf-8"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><mappers><!-- 注册 mapper 文件 --><mapper resource="UserDao.xml"/></mappers>
</configuration>

xml Mapper映射文件

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><insert id="insert">insert into user values(null,'赵六')</insert>
</mapper>

java 运行代码如下:

package com.lz;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;public class TestMybatis {@Testpublic void test() throws IOException {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory build = sqlSessionFactoryBuilder.build(stream);SqlSession sqlSession = build.openSession();int count = sqlSession.insert("insert");System.out.println(count);sqlSession.commit();}
}

在这里插入图片描述
在上述Java代码处

Resources.getResourceAsStream("mybatis-config.xml");

表示从类的根路径去查找文件,也就是这个目录下的文件。
在这里插入图片描述
关于mybatis-config.xml配置文件的mapper映射标签属性resource和url。
在这里插入图片描述
这里resource属性值依旧是上述resource下的文件,而url属性值要求的是绝对路径,格式为 file:///绝对路径
仔细看上述java代码,可以发现上述要想往数据库中成功插入数据,需要在执行完sql语句后,进行事务提交操作。这个和mybatis-config.xml配置文件中的配置有关,如下:
在这里插入图片描述
这个type的值可以为JDBC或者MANAGED。如果设置的值为JDBC,表示mybatis自己管理事务,因此我们需要自己手动提交事务;如果设置的值为MANAGED,表示mybatis不负责管理事务,事务管理交给其他容器来进行管理,如Spring。因此如果要进行SSM或者Spring Boot项目等,这个值应该设置为JDBC。

在这里插入图片描述
为了使控制台有日志输出信息,可以直接在mybatis-config.xml配置文件中添加如下配置即可。

<setting name="logImpl" value="STDOUT_LOGGING"/>

在这里插入图片描述
上述那个打印日志信息是mybatis自带的,如果想要引入其他依赖来打印日志信息,直接修改上述value值即可(比如SLF4J、LOG4J等,前提是引入对应的依赖。)

1-1. Mybatis 工具类的封装

package com.lz.untils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;public class SqlSessionUtils {private static SqlSessionFactory build;static {try {build = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));} catch (IOException e) {e.printStackTrace();}}public static SqlSession getSqlSession(){return build.openSession();}
}

1-2. Mybatis 通过集合或实体类传递参数-实现插入数据(增)

上述执行sql语句的参数是固定,其实可以通过#{}作为占位符来进行传递参数,如下:

    <insert id="insert2">insert into user values(null,#{name})</insert>

#{}占位符中值为map集合的key值。

@Test
public void test2() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();HashMap<String, Object> map = new HashMap<>();map.put("name","哆啦a梦");int count = sqlSession.insert("insert2", map);System.out.println(count);sqlSession.commit();sqlSession.close();}

运行结果如下:
在这里插入图片描述
当然也可以使用具体一个类来进行传递参数,如下:

@Testpublic void test3() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();User user = new User();user.setuName("皮卡丘");int count = sqlSession.insert("insert3", user);System.out.println(count);sqlSession.commit();sqlSession.close();}
package com.lz.entity;public class User {private Integer uId;private String uName;public void setuId(Integer uId) {this.uId = uId;}public void setuName(String uName) {this.uName = uName;}@Overridepublic String toString() {return "User{" +"uId=" + uId +", uName='" + uName + '\'' +'}';}
}
    <insert id="insert3">insert into user values(null,#{uName})</insert>

运行结果和上面一样,都能插入成功。

1-3. MyBatis 实现删除数据(删)

 @Testpublic void test4() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();int count = sqlSession.delete("del", 11);System.out.println(count);sqlSession.commit();sqlSession.close();}
<delete id="del">delete from user where u_id = #{uid}
</delete>

在这里插入图片描述
这里只有一个参数,因此在mapper.xml文件中占位符#{}里的变量名可以是任意符合变量命名规范的名称。

1-4. MyBatis 实现修改数据(改)

@Testpublic void test5() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();HashMap<Object, Object> map = new HashMap<>();map.put("uid",10);map.put("uname","嘻嘻哈哈");int count = sqlSession.update("update", map);System.out.println(count);sqlSession.commit();sqlSession.close();}
    <update id="update">update user set u_name=#{uname} where u_id =#{uid}</update>

在这里插入图片描述

1-5. MyBatis 实现查询数据(查)

@Testpublic void test6() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();User user = sqlSession.selectOne("select",10);System.out.println(user);sqlSession.close();}
<resultMap id="map1" type="com.lz.entity.User"><result property="uId" column="u_id"/><result property="uName" column="u_name"/>
</resultMap><select id="select" resultMap="map1">select u_id,u_name from user where u_id = #{uid}
</select>

这里可能需要麻烦一些,因为查询出的结果肯定是一个对象,如果不设置对应Java实体类变量与数据库表对应字段一一映射关系,那么就会报错。当然也可以给sql语句中的字段起别名也是可以的,如下:
在这里插入图片描述

如果想查询所有数据,只需要修改一下selectOne为selectList,当然不需要写入其他sql字段参数了,毕竟是查询所有数据,mapper.xml映射文件只需要修改一下sql语句即可。
在这里插入图片描述

2. MyBatis 配置文件中的一些标签和属性

MyBatis配置文件参考文档为:Mybatis 中文文档

2-1.environments标签

在这个标签下面可以配置多个数据库环境。为了区分使用的哪个数据库环境,environments标签下的每个environment标签都会有id属性,用于区分不同数据库环境,而environments标签default属性值为某个environment标签的id属性值,表示用的就是对应的数据库环境。

<environments default="development2"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mytest1?characterEncoding=utf-8"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment><environment id="development2"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mytest2?characterEncoding=utf-8"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments>

比如上述配置文件中所使用的环境就是id为development2的数据库环境,当然这只是默认情况下(如果在最终的Java代码中没有指定对应的数据库环境)。如果在Java代码中指定了使用哪个数据库环境,那么最终使用的数据库就是那个。

package com.lz;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;public class TestMybatis {@Testpublic void test() throws IOException {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory build = sqlSessionFactoryBuilder.build(stream,"数据库环境id值");SqlSession sqlSession = build.openSession();int count = sqlSession.insert("insert");System.out.println(count);sqlSession.commit();}
}

2-2. dataSource标签

dataSource标签为数据源标签。dataSource标签有一个type属性,这个属性有3个值可以进行选择,分别为UNPPOOLED、POOLED、JNDI。其中UNPPOOLED表示不使用数据库连接池技术,每次请求过来之后,都会创建新的Connection对象;POOLED表示使用mybatis自己实现的数据库连接池;JNDI表示集成其他第三方的数据连接池(比如Druid、C3P0等)。
type值为POOLED情况下,每次都会从连接池获取连接对象,用完之后会把连接对象归还给连接池,如下,因为用完之后又归还给了连接池,所以第二次获取得到的连接对象和第一次相同。
在这里插入图片描述
type值为UNPPOOLED情况下,每次都会创建新的连接对象,用完之后会关闭对应连接。
在这里插入图片描述

另外type属性不同,它们可以添加的属性也有所不同,如下:
在这里插入图片描述
在这里插入图片描述

2-3. properties标签

<properties resource="database.properties"/>

可以通过这个标签属性resource,让mybatis读取resources目录下的对应properties文件的数据,常用就是读取数据库连接信息,然后在配置文件下的environment标签的属性就可以进行对应赋值了。当然也可以使用url属性进行设置,只不过需要写绝对路径,格式为file:///文件的绝对路径

<environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${mysql.driver}"/><property name="url" value="${mysql.url}"/><property name="username" value="${mysql.username}"/><property name="password" value="${mysql.password}"/></dataSource>
</environment>

properties文件数据如下:

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mytest1?characterEncoding=utf-8
mysql.username=root
mysql.password=root

当然也可以直接在properties标签下定义property标签,在property标签内定义name和value,如下:

<properties><property name="driver" value="com.mysql.jdbc.Driver"/>。。。。
</properties>

在mybatis配置文件中如果要引入上述已经定义好的值,只需要使用${name值}即可。

3. MyBatis 面向接口进行CRUD & 小技巧

通过调用SqlSession对象的方法geMapper即可获取对应的Dao对象,需要传递参数对应Dao.class对象,前提是需要写接口已经对应的Mapper映射文件,如下:
UserDao接口文件

package com.lz.dao;import com.lz.entity.User;import java.util.List;public interface UserDao {User queryUserByid(Integer id);// 查询List<User> queryUsers();// 查询所有Integer add(User user);// 增Integer del(Integer uid);// 删Integer update(User user);// 改
}

UserMapper 映射文件

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.lz.dao.UserDao"><select id="queryUserByid" parameterType="Integer" resultType="com.lz.entity.User">select u_id as uId,u_name as uName from user where u_id=#{uid}</select><select id="queryUsers" resultType="com.lz.entity.User">select u_id as uId,u_name as uName from user</select><insert id="add" parameterType="User">insert into user values(null,#{uName})</insert><delete id="del" parameterType="Integer">delete from user where u_id=#{uid}</delete><update id="update" parameterType="User">update user set u_name = #{uName} where u_id=#{uId}</update>
</mapper>

需要注意的是mapper标签的namespace属性值必须为对应接口名,select、update、delete、insert 的id属性值必须为对应接口下的方法名。
单元测试运行代码:

package com.lz;import com.lz.dao.UserDao;
import com.lz.entity.User;
import com.lz.untils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;public class TestInterfaceCRUD {@Testpublic void test1(){SqlSession sqlSession = SqlSessionUtils.getSqlSession();UserDao userDao = sqlSession.getMapper(UserDao.class);List<User> users = userDao.queryUsers();users.forEach(user -> System.out.println(user));sqlSession.close();}@Testpublic void test3(){SqlSession sqlSession = SqlSessionUtils.getSqlSession();UserDao userDao = sqlSession.getMapper(UserDao.class);User user = userDao.queryUserByid(10);System.out.println(user);sqlSession.close();}@Testpublic void test2(){SqlSession sqlSession = SqlSessionUtils.getSqlSession();UserDao userDao = sqlSession.getMapper(UserDao.class);User user = new User();user.setuName("喜喜");int count = userDao.add(user);System.out.println(count);sqlSession.commit();sqlSession.close();}@Testpublic void test4(){SqlSession sqlSession = SqlSessionUtils.getSqlSession();UserDao userDao = sqlSession.getMapper(UserDao.class);Integer count = userDao.del(11);System.out.println(count);sqlSession.commit();sqlSession.close();}@Testpublic void test5(){SqlSession sqlSession = SqlSessionUtils.getSqlSession();UserDao userDao = sqlSession.getMapper(UserDao.class);User user = new User();user.setuId(10);user.setuName("哆啦A梦");Integer count = userDao.update(user);System.out.println(count);sqlSession.commit();sqlSession.close();}
}

3-1. mapper.xml 中 ${}和#{}的区别

#{}:底层使用PreparedStament,特点是先进行SQL语句的编译,然后给SQL语句的占位符?进行传值;
${}:底层使用Statement,特点是先进行SQL语句的拼接,然后再对SQL语句进行编译,存在SQL注入的风险
为此,优先使用#{},可以避免SQL注入的风险。
下述是使用${}进行SQL注入的示例代码,如下:
mappper映射文件:

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.lz.dao.UserDao"><select id="queryUsersByName" resultType="com.lz.entity.User" parameterType="String">select u_id as uId,u_name as uName from user where u_name ='${uName}'</select>
</mapper>

这是数据表中的数据:
在这里插入图片描述
然后我想查询数据库表user中有多少个u_name为赵六的用户,正常java代码如下:
在这里插入图片描述
正常情况下的确查询出的结果为3个,如果进行SQL注入,查询得到结果将会是user表中的全部数据,如下:
在这里插入图片描述
那么究竟在什么情况下使用#{},在什么情况下使用${}。如果需要在SQL语句中插入SQL关键字(比如desc、asc,表名等),使用${}
比如如果每天都会生成一个表,这个表存储的信息是当天注册某个网站的用户,表名是以时间日期形式拼成的,比如t_20250101。如果想查询一下某一天注册的用户数,此时只需要查询到对应的表即可,此时就可以使用${}。mapper映射文件的sql语句为:

select count(*) from t_${} 

如果把上述sql语句修改为#{},此时最终执行的sql会是这样,如下:

select count(*) from t_'t_20250101'

3-2. mapper.xml 实现模糊查询

在mapper.xml映射文件中可以写的sql语句为:

select u_id as uId,u_name as uName from user where u_name like '%${uName}%'

个人觉得下述这个更加安全,可以防止sql注入情况。

select u_id as uId,u_name as uName from user where u_name like concat('%',#{uName},'%')

3-3. mybatis-config.xml起别名 mapper.xml使用别名

在这里插入图片描述
上述mapper.xml映射文件中是不是觉得返回结果类型写这么长一串是不是觉得特别繁琐,其实可以其个别名,这样只需要写这个别名即可,如下,需要在mybatis配置文件进行配置才行。
在这里插入图片描述
上述这个属性alias可以省略,使用的时候可以直接写类的简名即可,如User、user等,不区分大小写。为了提高开发效率,也可以使用package起别名,此时需要写包的在项目下的路径即可,这样这个包下所有的实体类都起了别名,和上面一样,使用简名,如下:

<typeAliases><!-- 为 java 类型设置别名 -->
<!--        <typeAlias alias="User" type="com.lz.entity.User"/>--><package name="com.lz.entity"/>
</typeAliases>

此时在mapper.xml映射文件中就可以使用对应的别名了,如下:
在这里插入图片描述

3-4. mybatis-config.xml 配置mapper映射文件

<mappers><mapper resource=""></mapper><mapper url=""></mapper><mapper class=""></mapper>
</mappers>

mapper标签你的属性有3个,resource、url、class。resource:mapper.xml映射文件需要放到类路径才行,也就是项目的resources目录下;url:mapper.xml映射文件需要写绝对路径才行;class:这个值写的是mapper接口的全限定接口名,必须带有报名。同时mapper接口类与mapper.xml映射文件必须在同一个目录下,如下:

在这里插入图片描述

需要注意的是:在resources目录下新建目录不能采用com.lz.dao这种形式来创建多级目录,上述效果只能创建一个目录,目录名为com.lz.dao。如果要创建多级目录,只能一级一级去进行创建。最终创建出的目录显示效果和上述直接com.lz.dao这样的效果一样,但是打开项目结构就会发现不一样的。

3-5. 在IDEA中创建mybatis配置文件和mapper映射文件模板

在这里插入图片描述
点击File->settings->Editor->File and Code Templates,选择+新增模板,然后把对应的mybatis-config.xml,mapper.xml文件对应格式代码翻入之后保存即可。
在这里插入图片描述
在这里插入图片描述

3-6. mybatis 获取插入成功之后的主键id

需要在mapper映射文件中insert标签添加两个属性,分别为useGeneratedKeys,keyProperty,如下:
在这里插入图片描述
在这里插入图片描述
此时可以发现uid值不为null,是插入到数据库表的id主键。
在这里插入图片描述

4.MyBatis 参数处理 & 查询专题

mybatis框架自带有类型推断机制,所以大部分情况下mapper.xml映射文件parameterType属性都是可以省略不写的。但是写上,效率可能会更高。

4-1. mapper.xml映射文件之多参数

前面说过,如果where条件只有一个,那么在mapper.xml映射文件sql语句的编写的名可以随便写。如果是多个参数,则需要这样写:
在这里插入图片描述
可以采用的写法为arg0,arg1…或param1,param2…,表示的是在定义方法的形参位置。
当然也可以使用注解@Param来自定义命名,如下:

public interface UserDao{List<User> queryUserByid2(@Param(value="uId") Integer id, @Param(value = "uName") String uName);
}
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.lz.dao.UserDao"><select id="queryUserByid2" resultType="com.lz.entity.User">select u_id as uId,u_name as uName,birth from user where u_id=#{uId} or u_name like concat('%',#{uName},'%')</select></mapper>

在这里插入图片描述
在java代码这里进行断点操作,然后debug,可以发现代码执行到这:
在这里插入图片描述
在这里插入图片描述
发现这里使用的是jdk动态代理,然后会跳到这里。
在这里插入图片描述

发现它最终执行的还是SqlSession对象的selectList,如下:
在这里插入图片描述

4-2. MyBatis 查询结果之Map,List<Map>,Map<Map<String,Object>>

如果查询的结果没有对应的实体类进行接收,此时可以采用Map集合进行接收,参考代码如下:

public interface UserDao{Map<String,Object> queryByid3(Integer uid);
}
<mapper class="com.lz.dao.UserDao"><select id="queryByid3" returnType="Map">select * from user where u_id=#{uid}</select>
</mapper>

运行结果依旧可以输出的。
在这里插入图片描述
如果想要查询多个数据,采用List类型进行接收,参考如下:

public interface UserDao{List<Map<String,Object>> queryAll2();
}
<mapper class="com.lz.dao.UserDao"><select id="queryAll2" resultType="Map">select * from user</select>
</mapper>

运行结果如下:
在这里插入图片描述
但是上述并不怎么好从List中去得到满足条件的Map对象,为此,在此基础之上有了Map<String,Map<String,Object>>,把里层Map的u_id值作为外层Map的键值。如下:

public interface UserDao{@MapKey(value = "u_id")Map<Integer,Map<String,Object>> queryAll3();
}

使用注解@MapKey指定查询出结果哪个字段作为map的键值。

<mapper class="com.lz.dao.UserDao"><select id="queryAll3" resultType="Map">select * from user</select>
</mapper>

在这里插入图片描述

4-3. MyBatis 查询之结果集映射

在上述代码中如果查询的结果需要对应到对应实体类,采用的解决方法是对查询字段起别名(1),从而保证查询出的结果字段名与Java实体类属性名一一对应。其实,在mapper.xml映射文件中除了上述方法之外,还可以定义一个 结果集(2) 标签resultMap,在这个标签下写上对应数据库表字段名与Java实体类属性名一一对应关系,如下:

<mapper class="com.lz.dao.UserDao"><resultMap id="user" type="com.lz.entity.User"><id property="uId" column="u_id"/><result property="uName" column="u_name" javaType="String" jdbcType="VARCHAR"/><result property="birth" column="birth"/></resultMap><select id="queryUserByid" resultMap="user">select * from user where u_id=#{uid}</select>
</mapper>

在resultMap 下推荐使用id标签来指定主键字段对应关系,在标签内推荐使用javaType、jdbcType属性来指定对应Java类型,数据库字段类型,这样代码运行效率更高。
当然,上述效果也可以使用命名方式来实现,也就是开启 驼峰命名(3) 来实现自动映射。只需要在MyBatis配置文件中通过setting标签开发驼峰命名即可,如下:

<settings><setting name="mapUnderscoreToCamelCase" value="true"/>
</setting>

需要注意的是,应用这种方式:Java实体类变量名命名需要首字母小写,后面每个单词首字母大写;SQL数据表字段全部小写,单词之间采用下划线分割。比如如下:

sql : u_name
java: uName

在这里插入图片描述

5. 动态SQL

前面看到的sql语句where条件最多两个,如果存在多个条件,并且传递过来的参数却并不满足全部条件,也就是只有一些条件有参,有一些条件无参,这样虽然使用固定sql语句以及Java代码进行逻辑判断依旧是可以实现的,但是这样做比较繁琐,且重复代码比较多,此时就可以考虑使用动态sql,这样只需要写一条sql语句,在mapper.xml映射文件中做一些判断即可实现同样的效果。

5-1. 动态SQL-if标签、where标签、trim标签

if标签的test属性是必须的;test属性值是false或者true; 如果test属性值为true,则if标签下的sql语句就会被拼接,否则,则不会被拼接。如果这个参数传递是通过函数形参进行的,在没有使用注解的情况下,只能使用param1,param2,arg0,arg1来指明对应位置的参数;在使用注解的情况下,则是使用注解对应的value值;如果参数传递是通过实体类进行传递的,则是使用实体类的变量名;如果参数传递是通过Map集合来进行传递的,则是通过Map的键来进行的。

public interface UserDao{List<User> queryUsersByAll(Map<String,Object> map);
}
<mapper class="com.lz.dao.UserDao"><select id="queryUsersByAll" resultType="User">select * from userwhere<if test="uName != null and uName !='' ">u_name like concat('%',#{uName},'%') or</if><if test="startUid != null and endUid != null">( u_id &gt; #{startUid} and u_id &lt; #{endUid})</if></select>
</mapper>

上述语句在uName、startUid、endUid值都不为空的情况下是能正常运行的,但是如果三个参数有空的情况,则是有问题的,如下:
在这里插入图片描述
此时因为在sql语句多了一个关键词where,因此出现报错情况,为此可以考虑使用where标签,如下:

<mapper class="com.lz.dao.UserDao"><select id="queryUsersByAll" resultType="User">select * from user<where><if test="uName != null and uName !='' ">u_name like concat('%',#{uName},'%') or</if><if test="startUid != null and endUid != null">( u_id &gt; #{startUid} and u_id &lt; #{endUid})</if></where></select>
</mapper>

在这里插入图片描述

但是此时如果uName不为空,其他两个值均为空,此时语句中会报错,因为多了一个or关键词(where标签也是可以实现的,但是where标签只能去掉下面拼成的sql语句中前面的or、and,不能去掉后面的。),为此,也可以考虑使用trim标签,使用这个标签下拼成的sql语句可以在前加上sql关键词(比如where),也可以在后拼接sql关键词,并且还可以过滤前(prefixOverrides)、后(suffixOverrides)多出的sql关键词(比如and、or,且可以指定对应的sql关键词。),如下:

<mapper class="com.lz.dao.UserDao"><select id="queryUsersByAll" resultType="User">select * from user<trim prefix="where" prefixOverrides="or | and" suffixOverrides="or | and"><if test="uName != null and uName !='' ">u_name like concat('%',#{uName},'%') or</if><if test="startUid != null and endUid != null">( u_id &gt; #{startUid} and u_id &lt; #{endUid})</if></trim></select>
</mapper>

此时再执行上述说到的sql语句效果,运行代码可以正常执行。
在这里插入图片描述

5-2. 动态SQL-set标签

主要使用在update语句当中,用来生成set关键词,同时去掉多余的“,”,其等价如下:

<trim prefix="SET" suffixOverrides=",">...
</trim>
<mapper class="com.lz.dao.UserDao"><update id="update2" parameterType="user">update user<set><if test="uName != null and uName != ''">u_name = #{uName},</if><if test="birth != null">birth = #{birth}</if></set>where u_id = #{uId}</update>
</mapper>

经过测试,代码是可以正常输出的。
在这里插入图片描述

5-3. 动态SQL-choose、when、otherwise标签

类似java代码中if,else if,else,也就是最终只会把choose标签下面一个sql分支拼接到最终的sql中去。

if(...){...
}else if(...){...
}else{...
}
<mapper class="com.lz.dao.UserDao"><select id="queryUsers2" resultType="User">select * from userwhere (u_id &gt; 7 and u_id &lt; 11)<choose><when test="uName != null and uName != ''">and u_name like concat('%',#{uName},'%')</when><otherwise>or u_id = 14</otherwise></choose></select>
</mapper>

uName值不为空的情况下执行这条sql语句,如下:
在这里插入图片描述
uName值为空的情况下执行这条sql语句,如下:
在这里插入图片描述

5-4. 动态SQL-foreach标签

如果我想查询满足条件id的用户,此时传递过去的参数为List类型,这时就可以考虑使用foreach标签。
collection属性值可以为list、map、arg0…,当然也可以使用注解@Param来指明对应名。

<mapper class="com.lz.dao.UserDao"><select id="queryUsersByIds" resultType="User">select * from user whereu_id in<foreach collection="list" item="id" index="index" open="(" close=")" separator=",">#{id}</foreach></select>
</mapper>

在这里插入图片描述

5-5. 动态SQL-sql、include标签

主要是实现sql代码的复用,如下:

<mapper class="com.lz.dao.UserDao"><select id="queryUsersByIds" resultType="User"><include refid="selectFromUser"/>where u_id in<foreach collection="list" item="id" index="index" open="(" close=")" separator=",">#{id}</foreach></select><sql id="selectFromUser">select * from user</sql>
</mapper>

6. MyBatis 之高级映射(一对一,一对多)

在上面的代码,仅仅只是对一个数据库表的操作,实际业务中基本上是一对一或者一对多的情况,也就是需要至少涉及到两个数据库表。

package com.lz.entity;public class ClassRoom {private Integer cId;private String cName;public void setcId(Integer cId) {this.cId = cId;}public void setcName(String cName) {this.cName = cName;}@Overridepublic String toString() {return "ClassRoom{" +"cId=" + cId +", cName='" + cName + '\'' +'}';}
}
package com.lz.entity;public class Student {private Integer sId;private String sName;private Integer cId;public void setsId(Integer sId) {this.sId = sId;}public void setsName(String sName) {this.sName = sName;}public void setcId(Integer cId) {this.cId = cId;}@Overridepublic String toString() {return "Student{" +"sId=" + sId +", sName='" + sName + '\'' +", cId=" + cId +'}';}
}

上述为班级类、学生类。

6-1. 一对一映射-一个学生只能属于一个班级

一个学生只能属于一个班级,因此,可以在学生类加上属性ClassRoom类型的变量,如下:

package com.lz.dao;import com.lz.entity.Student;public interface StudentDao {Student selectBySid(Integer sid);// 通过学生id查询学生的信息
}

对应Mappper接口如上,对应的映射文件如下:

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.lz.dao.StudentDao"><resultMap id="studentMap" type="Student"><id property="sId" column="s_id" javaType="Integer"/><result property="sName" column="s_name" javaType="String"/><result property="cId" column="c_id" javaType="Integer"/><association property="classRoom" javaType="ClassRoom"><result property="cId" column="c_id" javaType="Integer"/><result property="cName" column="c_name" javaType="String"/></association></resultMap><select id="selectBySid" resultMap="studentMap">select s_id,s_name,s.c_id as 'c_id',c_name from student s,classroom cwhere s.c_id = c.c_id and s_id = #{sId}</select></mapper>

上述映射文件中需要使用映射到ClassRoom这个实体类上,为此,这里使用association 标签进行结构即可。

单元测试代码及结果如下:

package com.lz;import com.lz.dao.StudentDao;
import com.lz.entity.Student;
import com.lz.untils.SqlSessionUtils2;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;public class TestInterfaceCRUD2 {@Testpublic void test1(){SqlSession sqlSession = SqlSessionUtils2.getSqlSession();StudentDao sd = sqlSession.getMapper(StudentDao.class);Student student = sd.selectBySid(1);System.out.println(student);sqlSession.close();}
}

在这里插入图片描述

6-2. 一对多映射-一个班级拥有多个学生

一个班级拥有多个学生,因此需要在ClassRoom类中添加类型为List<Student>的变量,对应的接口如下:

package com.lz.dao;import com.lz.entity.ClassRoom;
import java.util.List;public interface ClassRoomDao {ClassRoom selectByCId(Integer cId);
}

对应映射文件如下:

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.lz.dao.ClassRoomDao"><resultMap id="classRoomMap" type="ClassRoom"><id property="cId" column="c_id"/><result property="cName" column="c_name"/><collection property="students" ofType="Student"><result property="sId" column="s_id"/><result property="sName" column="s_name"/></collection></resultMap><select id="selectByCId" resultMap="classRoomMap">select c.c_id as 'c_id',c_name,s_id,s_name from student s,classroom c where c.c_id = s.c_id and c.c_id = #{cId}</select></mapper>

这里需要用到collection标签,且在指定类型时用ofType来指定这个集合数据下类型。单元测试代码如下:

public class Test1{@Testpublic void test2(){SqlSession sqlSession = SqlSessionUtils2.getSqlSession();ClassRoomDao cd = sqlSession.getMapper(ClassRoomDao.class);ClassRoom classRoom = cd.selectByCId(1);System.out.println(classRoom);sqlSession.close();}
}

运行结果如下:
在这里插入图片描述

6-2. 一对多映射-分步查询

上述直接是多表查询,其实也可以通过分步查询实现上述效果的,参考如下:

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.lz.dao.ClassRoomDao"><resultMap id="classRoomMap2" type="ClassRoom"><id property="cId" column="c_id"/><result property="cName" column="c_name"/><collection property="students" select="com.lz.dao.StudentDao.selectByCid" column="c_id"/></resultMap><select id="selectByCId2" resultMap="classRoomMap2">select c_id,c_name from classroomwhere c_id = #{cId}</select></mapper>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.lz.dao.StudentDao"><select id="selectByCid" resultType="Student">select s_id,s_name,c_id from studentwhere c_id = #{cId}</select></mapper>

运行结果:
在这里插入图片描述
分步操作的好处:

  • 实现代码的复用,提高程序开发效率;
  • 支持延迟加载,也就是查询出的数据只有当用到的时候才执行对应的sql语句。
    首先在mybatis配置文件中开启延迟加载设置:
<settings><setting name="lazyLoadingEnabled" value="true"/>
</settings>

在这里插入图片描述
只获取班级名称只执行了一条sql语句,如上。
在这里插入图片描述
当获取对应班级的学生时,两条sql语句才执行。

7. MyBatis 逆向工程 generatorConfig.xml

所谓的逆向工程就是根据数据库表自动生成对应的实体类、对应的Mapper接口以及对应的Mapper.xml映射文件。为此需要引入对应的逆向工程插件的依赖。

<build><plugins><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.4.1</version><configuration><overwrite>true</overwrite></configuration><!--                这里只是是否重写已经存在的文件,也就是覆盖--><dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency></dependencies></plugin></plugins></build>

导入依赖之后,需要在resources目录下新建文件,文件名为:generatorConfig.xml,需要注意的是,这个名字必须是这个,文件下的配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><properties resource="jdbc.properties"/><context id="sqlserverTables" targetRuntime="MyBatis3">
<!--        targetRuntime 有两个值为:Mybatis3和Mybatis3SimpleMybatis3:生成的是增强版,除了基本的增删改查之外还有复杂的增删改查Mybatis3Simple:生成的是基础版,只有基本的增删改查
--><!--替换默认生成的dao-Example--><plugin type="org.mybatis.generator.plugins.RenameExampleClassPlugin"><property name="searchString" value="Example$" /><property name="replaceString" value="Impl" /></plugin><commentGenerator><!-- 是否生成注释代时间戳--><property name="suppressDate" value="true" /><!-- 是否去除自动生成的注释 true:是 : false:否 --><property name="suppressAllComments" value="true" /></commentGenerator><!-- 数据库链接URL、用户名、密码 --><jdbcConnection driverClass="${spring.datasource.driverClassName}"connectionURL="${spring.datasource.url}"userId="${spring.datasource.username}"password="${spring.datasource.password}"></jdbcConnection><!--默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer--><!--true,把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal--><!--        <javaTypeResolver>-->
<!--            <property name="forceBigDecimals" value="false" />-->
<!--        </javaTypeResolver>--><!--生成model模型,对应的包路径,以及文件存放路径(targetProject),targetProject可以指定具体的路径,如./src/main/java,--><!--也可以使用“MAVEN”来自动生成,这样生成的代码会在target/generatord-source目录下--><!--<javaModelGenerator targetPackage="com.joey.mybaties.test.pojo" targetProject="MAVEN">--><javaModelGenerator targetPackage="com.lz.entity" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><!-- 从数据库返回的值被清理前后的空格  --><property name="trimStrings" value="true" /></javaModelGenerator><!--对应的mapper.xml文件  --><sqlMapGenerator targetPackage="com.lz.dao" targetProject="src/main/resources"><property name="enableSubPackages" value="true"/>
<!--            是否开启子包--></sqlMapGenerator><!-- 对应的Mapper接口类文件 --><javaClientGenerator type="xmlMapper" targetPackage="com.lz.dao" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><!--            是否开启子包--></javaClientGenerator><!-- 列出要生成代码的所有表,这里配置的是不生成Example文件 --><!--    配置表信息tableName  表名domainObjectName    实体类名称--><table tableName="hotels" domainObjectName="Hotel"/></context>
</generatorConfiguration>

之后只需要运行对应的插件即可,如下:
在这里插入图片描述

之后便可以在项目下自动生成对应的文件,分别为对应实体类、对应实体类接口和Mapper.xml映射文件。把对应的Mapper.xml映射文件路径配置到MyBatis配置文件中即可使用。
在这里插入图片描述
上述使用的是Mybatis的逆向工程的增强版,具体参考上述逆向工程的配置文件的对应注释。因为使用的是增强版,所以除了生成上述三个文件之外,还生成了如下这个文件,如下:
在这里插入图片描述
这个文件命名原本是HotelExample,但是在逆向工程的配置文件中做了如下配置,因此命名变成了HotelImpl。
在这里插入图片描述
这个类是用于生成复杂的查询条件的,比如如下两个查询语句的参数都是HotelImpl类型:
在这里插入图片描述

单元测试代码如下:

public class TestOne{@Testpublic void test4(){SqlSession sqlSession = SqlSessionUtils2.getSqlSession();HotelMapper hotelMapper = sqlSession.getMapper(HotelMapper.class);HotelImpl hotel1 = new HotelImpl();hotel1.createCriteria().andIdBetween(2,4);List<Hotel> hotels = hotelMapper.selectByExample(hotel1);hotels.forEach(hotel->{System.out.println(hotel);});sqlSession.close();}
}

在这里插入图片描述

8. MyBatis 分页插件 PageHelper

本质上就是在查询sql语句后面拼上limit。。。字符串而已。

select * from user limit 0,3

关键词limit后面两个参数分别表示起始下标(从0开始),查询结果长度。
在这里插入图片描述
使用分页插件需要引入PageHelper依赖,如下:

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>4.1.3</version>
</dependency>

之后需要在mybatis配置文件中添加对应的拦截器的配置:

  <plugins><plugin interceptor="com.github.pagehelper.PageHelper"/></plugins>

单元测试代码如下:

public class TestOne{@Testpublic void test5(){SqlSession sqlSession = SqlSessionUtils2.getSqlSession();StudentDao studentDao = sqlSession.getMapper(StudentDao.class);PageHelper.startPage(1,1);List<Student> students = studentDao.selectByCid(1);students.forEach(student -> System.out.println(student));sqlSession.close();}
}

在这里插入图片描述
需要注意的是startPage第一个参数至少从1开始。

9. MyBatis 注解式开发

仅仅是对单表操作推荐使用,复杂sql语句操作还是使用上述xml方式来实现哈。

package com.lz.dao;import com.lz.entity.Student;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;import java.util.List;public interface StudentDao2 {@Select("select * from student where s_id=#{sid}")Student selectBySid(Integer sid);// 通过学生id查询学生的信息@Insert("insert into student values(null,#{sName},#{cId})")Integer add(Student stu);@Update("update student set s_name=#{sName} where s_id=#{sId}")Integer update(Student stu);@Delete("delete from student where s_id=#{sId}")Integer del(Integer sId);
}
package com.lz;import com.lz.dao.StudentDao;
import com.lz.dao.StudentDao2;
import com.lz.entity.Student;
import com.lz.untils.SqlSessionUtils2;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;public class TestIntefaceCRUD3 {@Testpublic void test1(){SqlSession sqlSession = SqlSessionUtils2.getSqlSession();StudentDao2 studentDao2 = sqlSession.getMapper(StudentDao2.class);Student student = studentDao2.selectBySid(1);System.out.println(student);sqlSession.close();}@Testpublic void test2(){SqlSession sqlSession = SqlSessionUtils2.getSqlSession();StudentDao2 studentDao2 = sqlSession.getMapper(StudentDao2.class);Student student = new Student();student.setsName("小明");student.setcId(1);Integer count = studentDao2.add(student);System.out.println(count);sqlSession.commit();sqlSession.close();}@Testpublic void test3(){SqlSession sqlSession = SqlSessionUtils2.getSqlSession();StudentDao2 studentDao2 = sqlSession.getMapper(StudentDao2.class);Student student = new Student();student.setsName("小花");student.setsId(6);System.out.println(studentDao2.update(student));sqlSession.commit();sqlSession.close();}@Testpublic void test4(){SqlSession sqlSession = SqlSessionUtils2.getSqlSession();StudentDao2 studentDao2 = sqlSession.getMapper(StudentDao2.class);Integer count = studentDao2.del(6);System.out.println(count);sqlSession.commit();sqlSession.close();}}

需要注意的是,我这里在MyBatis配置文件中开启了驼峰命名的,且Java实体类变量与数据库表字段命名符合对应规范的,如果你的Java类与对应数据库表字段命名不符合对应规范,可以这样操作,和在xml映射文件中设置resultMap类似。
在这里插入图片描述

相关文章:

后端:MyBatis

文章目录 1. MyBatis1-1. Mybatis 工具类的封装1-2. Mybatis 通过集合或实体类传递参数-实现插入数据(增)1-3. MyBatis 实现删除数据(删)1-4. MyBatis 实现修改数据(改)1-5. MyBatis 实现查询数据(查) 2. MyBatis 配置文件中的一些标签和属性2-1.environments标签2-2. dataSour…...

CBAM-2018学习笔记

名称&#xff1a; Convolutional Block Attention Module (CBAM) 来源&#xff1a; CBAM: Convolutional Block Attention Module 相关工作&#xff1a; #ResNet #GoogleNet #ResNeXt #Network-engineering #Attention-mechanism 创新点&#xff1a; 贡献&#xff1a; 提…...

HTML根元素<html>的语言属性lang:<html lang=“en“>

诸神缄默不语-个人CSDN博文目录 在编写HTML页面时&#xff0c;通常会看到<html lang"en">这行代码&#xff0c;特别是在网页的开头部分&#xff0c;就在<!DOCTYPE html>后面。许多开发者可能对这个属性的含义不太了解&#xff0c;它到底有什么作用&…...

解决github无法clone的问题

问题背景 (base) ~$ git clone https://github.com/isaac-sim/IsaacLab.git 正克隆到 IsaacLab... fatal: 无法访问 https://github.com/isaac-sim/IsaacLab.git/&#xff1a;gnutls_handshake() failed: Error in the pull function.解决办法 我使用了代理&#xff0c;需要配…...

第1章:Python TDD基础与乘法功能测试

写在前面 这本书是我们老板推荐过的&#xff0c;我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后&#xff0c;我突然思考&#xff0c;对于测试开发工程师来说&#xff0c;什么才更有价值呢&#xff1f;如何让 AI 工具更好地辅助自己写代码&#xff0c;或许…...

【华为路由/交换机的ftp文件操作】

华为路由/交换机的ftp文件操作 PC&#xff1a;10.0.1.1 R1&#xff1a;10.0.1.254 / 10.0.2.254 FTP&#xff1a;10.0.2.1 S1&#xff1a;无配置 在桌面创建FTP-Huawei文件夹&#xff0c;里面创建config/test.txt。 点击上图中的“启动”按钮。 然后ftp到server&#xff0c;…...

【HBuilderX 中 Git 的使用】

目录&#xff1a; 一&#xff1a;安装必要的版本控制工具二&#xff1a;把Github上的项目克隆到本地三&#xff1a;将本地的项目上传到Github上 一&#xff1a;安装必要的版本控制工具 1️⃣ 安装 TortoiseGit 工具&#xff0c;下载地址&#xff1a;https://tortoisegit.org/do…...

语言模型的价值定位与技术突破:从信息处理到创新认知

标题&#xff1a;语言模型的价值定位与技术突破&#xff1a;从信息处理到创新认知 文章信息摘要&#xff1a; 当前语言模型的核心价值主要体现在信息综合与处理能力上&#xff0c;用户友好的交互界面是其成功关键。在模型计算机制方面&#xff0c;推理能力的实现包括chain-of-…...

使用Websocket进行前后端实时通信

1、引入jar&#xff0c;spring-websocket-starter <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency> 2、配置websocket config import org.springframe…...

【Leetcode 热题 100】70. 爬楼梯

问题背景 假设你正在爬楼梯。需要 n n n 阶你才能到达楼顶。 每次你可以爬 1 1 1 或 2 2 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 数据约束 1 ≤ n ≤ 45 1 \le n \le 45 1≤n≤45 解题过程 昨天刚刚当成扩展题做过&#xff0c;今天遇到了再写一次。…...

STM32更新程序OTA

STM32的OTA&#xff08;Over-The-Air&#xff09;更新程序是一种通过无线通信方式&#xff0c;为设备分发新软件、配置甚至更新加密密钥的技术。以下是关于STM32 OTA更新程序的详细介绍&#xff1a; 一、OTA升级流程 STM32的OTA升级流程通常包括以下几个关键步骤&#xff1a;…...

【海贼王航海日志:前端技术探索】一篇文章带你走进JavaScript(三)

目录 1 -> WebAPI背景知识 1.1 -> 什么是WebAPI 1.2 -> 什么是API 1.3 -> 什么是DOM 1.3.1 -> DOM树 2 -> 获取元素 2.1 -> querySelector 2.2 -> querySelectorAll 3 -> 事件初识 3.1 -> 基本概念 3.2 -> 事件三要素 4 -> 操…...

计算机创造的奇迹——C语言

一.简介 C语言是一种较早的程序设计语言&#xff0c;诞生于1972年的贝尔实验室。1972 年&#xff0c;Dennis Ritchie 设计了C语言&#xff0c;它继承了B语言的许多思想&#xff0c;并加入了数据类型的概念及其他特性。 尽管C 语言是与 UNIX 操作系统一起被开发出来的&#xff…...

TypeScript - 利用GPT辅助学习

TypeScript 一、基础1. 安装 TypeScript2. 创建你的第一个 TypeScript 文件3. 编译 TypeScript 代码4. 变量声明与类型注解5. 函数与类型注解6. 总结 二、进阶常用类型1. 类型别名2. 对象类型3. 类型断言4.typeof 操作符 高级类型1. 类2. 交叉类型3. 泛型与 keyof4. 索引签名类…...

Node.js 与 JavaScript 是什么关系

JavaScript 是一种编程语言&#xff0c;而 Node.js 是 JavaScript 的一个运行环境&#xff0c;它们在不同的环境中使用&#xff0c;具有一些共同的语言基础&#xff0c;但也有各自独特的 API 和模块&#xff0c;共同推动着 JavaScript 在前后端开发中的广泛应用。 一、基础语言…...

Spring MVC:设置响应

目录 引言 1. 返回静态页面 1.1 Spring 默认扫描路径 1.2 RestController 1.2.1 Controller > 返回页面 1.2.2 ResponseBody 2. 返回 HTML 2.1 RequestMapping 2.1.1 produces(修改响应的 Content-Type) 2.1.2 其他属性 3. 返回 JSON 4. 设置状态码 4.1 HttpSer…...

c#实现当捕获异常时自动重启程序

首先&#xff0c;需要说明这并不是一个推荐的做法&#xff0c;只有在你确实有这样的需求时才考虑这么做。 以下是AI的回答&#xff0c;为什么不推荐这么做&#xff0c;供参考。 在C#中&#xff0c;如果你在catch语句中尝试重启程序自身&#xff0c;可能会遇到以下几个问题&…...

游戏引擎学习第84天

仓库:https://gitee.com/mrxiao_com/2d_game_2 我们正在试图弄清楚如何完成我们的世界构建 上周做了一些偏离计划的工作&#xff0c;开发了一个小型的背景位图合成工具&#xff0c;这个工具做得还不错&#xff0c;虽然是临时拼凑的&#xff0c;但验证了背景构建的思路。这个过…...

Python----Python高级(文件操作open,os模块对于文件操作,shutil模块 )

一、文件处理 1.1、文件操作的重要性和应用场景 1.1.1、重要性 数据持久化&#xff1a; 文件是存储数据的一种非常基本且重要的方式。通过文件&#xff0c;我们可 以将程序运行时产生的数据永久保存下来&#xff0c;以便将来使用。 跨平台兼容性&#xff1a; 文件是一种通用…...

“AI 大模型内容安全审核软件系统:守护网络世界的卫士

在如今这个信息爆炸的互联网时代&#xff0c;网络上的内容那是五花八门、层出不穷。这时候&#xff0c;咱就得靠 AI 大模型内容安全审核软件系统来给咱把把关了。 咱就说社交媒体平台吧&#xff0c;每天都有海量的用户在上面发布文字、图片、视频啥的。要是没有一个靠谱的审核系…...

快速入门Python的异步库:asyncio

目录 异步 Python asyncio 1. async 关键字 2. await 关键字 3. asyncio.run() 4. asyncio.sleep() 5. 协程 程序执行流程 可以被等待的异步 协程 任务 Futures 任务 asyncio.create_task() await 和任务结果 Reference 异步 我们首先先来谈谈异步&#xff0c;…...

大美祖国-使用Java盘点那些在地名中出现最多的汉字

目录 前言 一、地名数据准备 1、全国地名数据 二、使用Java进行汉字统计 1、汉字数据统计 2、汉字分割统计 三、浅谈地名汉字名次及其意义 1、山、城、江、河 2、安、平、宁 3、地名中的方位 四、总结 前言 在中国这片古老而又年轻的土地上&#xff0c;地名不仅仅是地…...

华为OD机试E卷 --羊、狼、农夫过河--24年OD统一考试(Java JS Python C C++)

文章目录 题目描述输入描述输出描述用例题目解析JS算法源码Java算法源码python算法源码c算法源码c++算法源码题目描述 羊、狼、农夫都在岸边,当羊的数量小于狼的数量时,狼会攻击羊,农夫则会损失羊。农夫有一艘容量固定的船,能够承载固定数量的动物。 要求求出不损失羊情况…...

Java - WebSocket

一、WebSocket 1.1、WebSocket概念 WebSocket是一种协议&#xff0c;用于在Web应用程序和服务器之间建立实时、双向的通信连接。它通过一个单一的TCP连接提供了持久化连接&#xff0c;这使得Web应用程序可以更加实时地传递数据。WebSocket协议最初由W3C开发&#xff0c;并于2…...

JavaWeb开发(十五)实战-生鲜后台管理系统(二)注册、登录、记住密码

1. 生鲜后台管理系统-注册功能 1.1. 注册功能 &#xff08;1&#xff09;创建注册RegisterServlet&#xff0c;接收form表单中的参数。   &#xff08;2&#xff09;service创建一个userService处理业务逻辑。   &#xff08;3&#xff09;RegisterServlet将参数传递给ser…...

【深度学习】利用Java DL4J 训练金融投资组合模型

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s…...

【MySQL篇】事务的认识以及四大特性

何为事务&#xff1f; 事务&#xff08;Transaction&#xff09;是指一组操作的集合&#xff0c;这些操作要么全部执行成功&#xff0c;要么全部不执行。事务通常用于保证数据库的一致性、完整性和可靠性&#xff0c;确保数据的完整性与正确性。 有效避免部分执行&#xff0…...

CSS 网络安全字体

适用于 HTML 和 CSS 的最佳 Web 安全字体 下面列出了适用于 HTM L和 CSS 的最佳 Web 安全字体&#xff1a; Arial (sans-serif)Verdana (sans-serif)Helvetica (sans-serif)Tahoma (sans-serif)Trebuchet MS (sans-serif)Times New Roman (serif)Georgia (serif)Garamond (se…...

实战演示:利用ChatGPT高效撰写论文

在当今学术界&#xff0c;撰写论文是一项必不可少的技能。然而&#xff0c;许多研究人员和学生在写作过程中常常感到困惑和压力。幸运的是&#xff0c;人工智能的快速发展为我们提供了新的工具&#xff0c;其中ChatGPT便是一个优秀的选择。本文将通过易创AI创作平台&#xff0c…...

显卡(Graphics Processing Unit,GPU)架构详细解读

显卡架构主要分为两大类&#xff1a;GPU 核心架构&#xff08;也称为图形处理单元架构&#xff09;和显卡的其他组件&#xff08;如内存、控制器、输出接口等&#xff09;。本篇文章将对显卡架构进行详细分析&#xff0c;重点介绍 GPU 核心架构、显卡计算单元、显存结构、显卡管…...

OpenCV相机标定与3D重建(63)校正图像的畸变函数undistort()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 转换图像以补偿镜头畸变。 该函数通过变换图像来补偿径向和切向镜头畸变。 此函数仅仅是 initUndistortRectifyMap&#xff08;使用单位矩阵 R…...

人工智能-机器学习之多分类分析(项目实战二-鸢尾花的多分类分析)

Softmax回归听名字&#xff0c;依然好像是做回归任务的算法&#xff0c;但其实它是去做多分类任务的算法。 篮球比赛胜负是二分类&#xff0c;足球比赛胜平负就是多分类 识别手写数字0和1是二分类&#xff0c;识别手写数字0-9就是多分类 Softmax回归算法是一种用于多分类问题…...

【JDBC】数据库连接的艺术:深入解析数据库连接池、Apache-DBUtils与BasicDAO

文章目录 前言&#x1f30d; 一.连接池❄️1. 传统获取Conntion问题分析❄️2. 数据库连接池❄️3.连接池之C3P0技术&#x1f341;3.1关键特性&#x1f341;3.2配置选项&#x1f341;3.3使用示例 ❄️4. 连接池之Druid技术&#x1f341; 4.1主要特性&#x1f341; 4.2 配置选项…...

【Envi遥感图像处理】006:影像融合(高光谱+多光谱)的方法

文章目录 一、图像融合概述二、加载数据三、图像融合操作四、结果比对五、高光谱与多光谱一、图像融合概述 图像融合是指将不同类型传感器的影像进行融合,既能使图向具有较高的空间分辨率,又具有多光谱的特性。 二、加载数据 三、图像融合操作 在ENvi中,图像融合使用的工具…...

C语言内存之旅:从静态到动态的跨越

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文一 动态内存管理的必要性二 动态…...

Git本地搭建

Git本地搭建 &#xff08;项目突然不给创建仓库了&#xff0c;为了方便管理项目只能自己本地搭建git服务&#xff09; 为了在本地搭建Git环境并实现基本的Git操作&#xff0c;步骤如下&#xff1a; 安装Git软件 ‌Windows‌&#xff1a;从Git官方网站下载并安装适用于Windows…...

电商|基于java的农业电商系统(源码+数据库+文档)

农业电商系统 目录 基于java的农业电商系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 前台&#xff1a; 后台&#xff1a; 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️…...

c语言分支和循环

文章目录 前言 一、分支结构 if语句 switch语句 三目运算符 二、循环结构 while循环 do-while循环 for循环 循环嵌套 循环控制语句 总结 前言 分支和循环是C语言中非常重要的控制结…...

大象机器人发布首款穿戴式数据采集器myController S570,助力具身智能数据收集!

myController S570 具有较高的数据采集速度和远程控制能力&#xff0c;大大简化了人形机器人的编程。 myController S570 是一款可移动的轻量级外骨骼&#xff0c;具有 14 个关节、2 个操纵杆和 2 个按钮&#xff0c;它提供高数据采集速度&#xff0c;出色的兼容性&#xff0c…...

【HarmonyOS NEXT】华为分享-碰一碰开发分享

关键词&#xff1a;鸿蒙、碰一碰、systemShare、harmonyShare、Share Kit 华为分享新推出碰一碰分享&#xff0c;支持用户通过手机碰一碰发起跨端分享&#xff0c;可实现传输图片、共享wifi等。我们只需调用系统 api 传入所需参数拉起对应分享卡片模板即可&#xff0c;无需对 U…...

基于python+Django+mysql鲜花水果销售商城网站系统设计与实现

博主介绍&#xff1a;黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者&#xff0c;CSDN博客专家&#xff0c;在线教育专家&#xff0c;CSDN钻石讲师&#xff1b;专注大学生毕业设计教育、辅导。 所有项目都配有从入门到精通的基础知识视频课程&#xff…...

Linux C\C++方式下的文件I/O编程

【图书推荐】《Linux C与C一线开发实践&#xff08;第2版&#xff09;》_linux c与c一线开发实践pdf-CSDN博客 《Linux C与C一线开发实践&#xff08;第2版&#xff09;&#xff08;Linux技术丛书&#xff09;》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 Lin…...

2025寒假备战蓝桥杯01---朴素二分查找的学习

文章目录 1.暴力方法的引入2.暴力解法的思考 与改进3.朴素二分查找的引入4.朴素二分查找的流程5.朴素二分查找的细节6.朴素二分查找的题目 1.暴力方法的引入 对于下面的这个有序的数据元素的组合&#xff0c;我们的暴力解法就是挨个进行遍历操作&#xff0c;一直找到和我们的这…...

AI时代:弯道超车的新思维与实践路径

大家好&#xff0c;我是herosunly。985院校硕士毕业&#xff0c;现担任算法研究员一职&#xff0c;热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名&#xff0c;CCF比赛第二名&#xff0c;科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的…...

HunyuanDiT代码笔记

HunyuanDiT 是由腾讯发布的文生图模型&#xff0c;适配中英双语。 在模型方面的改进&#xff0c;主要包括&#xff1a; transformer结构text encoderpositional encoding Improving Training Stability To stabilize training, we present three techniques: We add layer nor…...

C++: Dtrees:load(constg String filepath, const String nodeName)中nodeName参数含义

1. nodeName 的作用 当你保存模型时&#xff0c;整个决策树会被序列化到一个 XML 或 YAML 文件中。nodeName 是加载时指定的一个逻辑路径&#xff0c;用于从文件中找到某个节点或子结构&#xff0c;而不是存储在文件中的字段。如果你不指定 nodeName&#xff0c;OpenCV 默认会…...

项目练习:若依后台管理系统-后端服务开发步骤(springboot单节点版本)

文章目录 1、用Maven搭建项目脚手架&#xff0c;父子工程依赖。2、引入SpringBoot Web容器依赖3、引入Mybatisdruid依赖4、实现接口查询数据5、整合logback日志功能 1、用Maven搭建项目脚手架&#xff0c;父子工程依赖。 root模块的pom添加plugin配置 <build><plugins…...

Ubuntu安装docker

snap install docker # version 27.2.0, or apt install podman-docker # version 3.4.4ds1-1ubuntu1.22.04.2 apt install docker.io # version 24.0.7-0ubuntu2~22.04.1 我应该安装哪一个&#xff0c;部署企业级应用? 在部署企业级应用时&#xff0c;选择合适的容器化…...

windows11下 podman-desktop 复制插件文件 到 RabbitMQ 容器内,并启用

目的&#xff1a; 刚启用的 RabbitMQ 容器&#xff0c;发现没有rabbitmq_delayed_message_exchange 插件&#xff0c;开始手动安装 官网 https://www.rabbitmq.com/community-plugins 或 https://github.com/rabbitmq/rabbitmq-delayed-message-exchange 下载rabbitmq_delay…...

Quickstart C++ with cmake, visualstudio | CPP

本文属于 C 系列文章&#xff0c;下一篇文章见 Quick get started with vcpkg, windows visual studio | CPP 目录 cmake-visualstudio-quickstartDepsConfigureBuild with CLILINKS cmake-visualstudio-quickstart https://github.com/hailiang-wang/cmake-visualstudio-quic…...