1,引入mybatis的依赖
<dependencies> <dependency> <groupId>org.mybatisgroupId> <artifactId>mybatisartifactId> <version>3.5.6version> dependency> <dependency> <groupId>log4jgroupId> <artifactId>log4jartifactId> <version>1.2.17version> dependency> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>8.0.27version> dependency> <dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <version>4.13version> <scope>testscope> dependency> dependencies>
2, 编写mybatis的核心配置文件 sqlMapConfig.xml
主要包含: 引入数据库环境的配置 配置mapper映射文件(db.properties,log4j.properties:显示日志)
「log4j.properties」等文件 https://www.aliyundrive.com/s/iJbbwHMkqzb
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="db.properties">properties> <settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> settings> <typeAliases> <package name="com.cq.pojo">package> typeAliases> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC">transactionManager> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> dataSource> environment> environments> <mappers> <package name="com.cq.dao"/> mappers> configuration>
3 编写mybatis的映射文件
要和mapper接口中名字保持一致目录结构也要一致,映射文件放到resource目录下
4 映射文件UserDao.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.cq.dao.UserDao"> <select id="fingUser" parameterType="int" resultType="user"> select * from user where id = #{id} select> mapper>
注意:
namespace:说明是那个接口
id:是接口中的方法名
parameterType:是输入参数类型
resultType:是输出参数类型
如果参数是集合那么参数是他们的泛型,一般参数是全限定类型,但是mybatis提供了一些参数的别名,也可以自己定义别名在核心配置文件中
//在pojo包下类的别名,是其类名的小写
@Test public void test01(){ Map<String,Object> map = new HashMap<String,Object>(); map.put("sex","男"); map.put("address","上海"); List<User> users = mapper.fingAll1(map); for (User user : users) { System.out.println(user); } }
<select id="fingAll2" resultType="com.cq.pojo.User"> select * from user where sex = '${param1}' and address = '${param2}'; select>
public List<User> fingAll3(@Param("sex") String sex, @Param("address") String address);
/* 注解的分类 @Select 查询 @Update 修改 @Delete 删除 @Insert 增加 */ @Select("select * from user") public List<User> fingAll(); @Select("select * from user where id = #{id}") public User fingGetId(Integer id);
用连接池的目的主要是为了减少我们获取连接所消耗的时间。
在sqlMapConfig.xml文件中进行配置连接池 POOLED 支持连接池 UNPOOLED 不支持连接池(每次连接都需要重新new 连接对象耗时)
<environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC">transactionManager> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> dataSource> environment> environments>
POOLED支持连接池:用户在需要连接数据库时会从连接池中获取连接对象,使用完毕后归还给连接池
连接池又分为活动连接池和空闲连接池 会先从活动连接池中获取连接对象如果活动连接池中已经用完,再看空闲连接池 活动连接池的初始大小为10 空闲连接池初始大小为 5 连接池的本质是List集合
何为事务
事务指的是一组逻辑操作,这些操作是最小单位不可分割的,这些逻辑操作要么全部执行成功,要么全部执行失败
事务的ACID四种特性
ACID是原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)的缩写,这四种状态的意思是:
1、原子性
即不可分割,事务要么全部被执行,要么全部不执行。如果事务的所有子事务全部提交成功,则所有的数据库操作被提交,数据库状态发生变化;如果有子事务失败,则其他子事务的数据库操作被回滚,即数据库回到事务执行前的状态,不会发生状态转换
2、一致性
事务的执行使得数据库从一种正确状态转换成另外一种正确状态
3、隔离性
在事务正确提交之前,不允许把事务对该数据的改变提供给任何其他事务,即在事务正确提交之前,它可能的结果不应该显示给其他事务
4、持久性
事务正确提交之后,其结果将永远保存在数据库之中,即使在事务提交之后有了其他故障,事务的处理结果也会得到保存
在进行增删改操作时,如果不commit,数据库中的数据不会发生变化,因为 回滚了rolling back
当最后手动提后
sqlSession.commit();//提交事务 committing
为啥要使用动态SQL
原因:Mybatis的映射文件中,前面我们的 SQL都是比较简单的,有些时候业务逻辑复杂时,我们的SQL是动态变化的,此时在前面的学习中我们的SQL就不能满足要求了。
我们根据实体类的不同取值,使用不同的SQL语句来进行查询。比如在id如果不为空时可以根据 id查询,如果username不空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到 。where 1 = 1是为了和后面的and语句进行sql拼接
<select id="fingAll" parameterType="user" resultType="user"> select * from user where 1 = 1 <if test="username != null and username != ''"> and username = #{username} if> <if test="birthday != null and birthday != ''"> and birthday = #{birthday} if> <if test="sex != null and sex != ''"> and sex = #{sex} if> <if test="address != null and address != ''"> and address = #{address} if> select>
为了简化上面where 1=1的条件拼装,我们可以采用标签来简化开发。使用where标签将if标签代码块包起来,将1=1条件去掉。
<select id="fingAll1" resultType="user" parameterType="user"> select * from user <where> <if test="username != null and username != ''"> and username = #{username} if> <if test="birthday != null and birthday != ''"> and birthday = #{birthday} if> <if test="sex != null and sex != ''"> and sex = #{sex} if> <if test="address != null and address != ''"> and address = #{address} if> where> select>
通过set标签来实现动态的修改
<update id="updateUser" parameterType="user"> update user <set> <if test="username != null and username != ''"> username = #{username}, if> <if test="birthday != null"> birthday = #{birthday}, if> <if test="sex != null and sex != ''"> sex = #{sex}, if> <if test="address != null and address != ''"> address = #{address}, if> set> where id = #{id} update>
测试类
public class MyTest {
UserDao mapper;
SqlSession sqlSession;
InputStream in;
@Before
public void before()throws Exception{
//加载mybatis的核心配置文件
in = Resources.getResourceAsStream("sqlMapConfig.xml");
//创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//创建SqlSessionFactory对象
SqlSessionFactory build = builder.build(in);
//创建SqlSession对象
sqlSession = build.openSession(ExecutorType.BATCH);//开启批处理
//生成接口的代理
mapper = sqlSession.getMapper(UserDao.class);
}
@After
public void after()throws Exception{
sqlSession.close();
//关闭资源
in.close();
}
@Test
public void test04()throws Exception {
User user = new User();
user.setId(51);
user.setUsername("赵云");
user.setBirthday(new Date());
user.setAddress("常山");
user.setSex("男");
mapper.updateUser(user);
sqlSession.commit();
}
}
@Befer @After 这是mybatis提供的注解 @Befer表示在@Test之前执行 @Afer表示在@Test之后执行
insert into 表(字段名) values(值):没有添加的字段为null
<sql id="key"> <trim suffixOverrides=","> <if test="username != null and username != ''"> username, if> <if test="birthday != null"> birthday, if> <if test="sex != null and sex != ''"> sex, if> <if test="address != null and address != ''"> address, if> trim> sql> <sql id="value"> <trim suffixOverrides=","> <if test="username != null and username != ''"> #{username}, if> <if test="birthday != null"> #{birthday}, if> <if test="sex != null and sex != ''"> #{sex}, if> <if test="address != null and address != ''"> #{address}, if> trim> sql> <insert id="addUser" parameterType="user"> insert into user(<include refid="key">include>) values (<include refid="value">include>) insert>
相当于: if else if else
<select id="fingByCondition" parameterType="user" resultType="user"> select * from user <where> <choose> <when test="username != null and username != ''"> username = #{username} when> <when test="sex != null and sex != ''"> sex = #{sex} when> <otherwise> id = #{id} otherwise> choose> where> select>
delete from user where id in ( < foreach collection="ids" item="id" separator=",">{id}
)collection:数据类型
item:别名
separator:以什么为分割
当我们传递一个 List 实例或者数组作为参数对象传给 MyBatis。当你这么做的时候,MyBatis 会自动将它包装在一个 Map 中,用名称在作为键。List 实例将会以“list”作为键,而数组实例将会以“array”作为键。所以,当我们传递的是一个List集合时,mybatis会自动把我们的list集合包装成以list为Key值的map。
映射文件:
<insert id="add" parameterType="user"> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) insert>
测试
@Test public void test06()throws Exception{ List<User> list = new ArrayList<User>(); User user = new User("测试1", new Date(), "男", "中国"); User user2 = new User("测试2", new Date(), "男", "中国"); User user3 = new User("测试3", new Date(), "男", "中国"); User user4 = new User("测试4", new Date(), "男", "中国"); list.add(user); list.add(user2); list.add(user3); list.add(user4); for (User user1 : list) { mapper.add(user1); }; sqlSession.commit(); }
通过日志打印mybatis解析的sql
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yq2Znsfm-1654780794615)(G:\image\java\mybatis\微信图片_20220607193507.png)]
每执行一次添加语句都会和执行一次sql,由于insert语句多次执行,造成执行效率很低
设置批处理
位置1
在sqlMapConfig.xml核心文件进行开启批处理
全局有效
位置2
@Before public void before()throws Exception{ //加载mybatis的核心配置文件 in = Resources.getResourceAsStream("sqlMapConfig.xml"); //创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //创建SqlSessionFactory对象 SqlSessionFactory build = builder.build(in); //创建SqlSession对象 sqlSession = build.openSession(ExecutorType.BATCH);//开启批处理 //生成接口的代理 mapper = sqlSession.getMapper(UserDao.class); }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O31qIkO7-1654780794616)(G:\image\java\mybatis\微信图片_20220607194114.png)]
开启批处理后只会调用一次sql
底层:insert into 表() values(),(),(),
分为一级缓存和二级缓存
一级缓存有称为sqlSession级别的缓存(本质是一个map结构):当关闭sqlSession或者数据库中原本缓存的数据发生变化此时缓存就会失效
mybatis缓存无法实现数据的实时同步
二级缓存需要开启.多个sqlSession公用一个二级缓存
查询顺序
先查二级缓存如果未命中,就查一级缓存如果依旧没有命中,就查数据库。一级缓存中的数据会自动写到二级缓存中
表和表之间的关系:一对一,一对多,多对多
一对一查询
主要分析出主表和关联表
例如查询账户信息及其对应的用户信息,这就是一对一的关系,其中账户表是主表,用户信息是关联表
此时我们会有一个问题,就是查询出来的字段在pojo包下没有与之对应的实体
方法1,使用继承,定义一个类具有和主表相同的属性继承关联表的属性这样就可以封装查询出来的数据
方法2,主表中需要维护关联表的完整性
public class Account implements Serializable { private Integer id; private Integer uid; private Double money; private User user;//引入1的类
此时与之对应的数据库中的表和实体字段不一致,我们可以通过手动映射的方式 resultMap
<resultMap id="accountMap" type="account"> <id column="id" property="id">id> <result column="uid" property="uid">result> <result column="money" property="money">result> <association property="user" javaType="user"> <id property="id" column="id">id> <result property="username" column="username">result> <result property="birthday" column="birthday">result> <result property="sex" column="sex">result> <result property="address" column="address">result> association> resultMap> <select id="fingAll1" resultMap="accountMap"> SELECT * from account as a,user as u where a.uid = u.id select>
一对多
需求:查询用户及其账户的信息:一对多
同理在1的实体中维护多的完整性List集合
public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; private List<Account> account;//多的
手动映射
<resultMap id="userMap" type="user"> <id column="id" property="id">id> <result property="username" column="username">result> <result property="birthday" column="birthday">result> <result property="sex" column="sex">result> <result property="address" column="address">result> <collection property="account" ofType="account"> <id column="id" property="id">id> <result property="id" column="id">result> <result property="uid" column="uid">result> collection> resultMap> <select id="fingUser" resultMap="userMap"> SELECT * from user as u,account as a where u.id = a.UID select>
多对多
我们使用Mybatis 实现一对多关系的维护。多对多关系其实我们看成是双向的一对多关系。
同一对多的处理相同
问题: 在一对多中,当我们一个用户,它有100个账户。
在查询用户的时候,要不要把关联的账户查询出来?
在查询账户的时候,要不要把关联的用户查询出来?
答案:
在查询用户时,用户下的账户信息应该是什么时候用,什么时候查询。
在查询账户时,账户所属的用户信息应该是随着账户信息一起查询出来的。
什么是延迟加载:
在真正使用数据的时候才发起查询,不用的时候不查询。按需加载(延迟加载)
什么是立即加载:
不管用不用,只要一调用方法,立马查询出来
在sqlMapConfig.xml中配置延迟加载策略
<settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> settings>
association的延迟加载(1对1延迟加载)
AccountDao.xml映射文件
<resultMap id="accountMap" type="account"> <id column="id" property="id">id> <result property="uid" column="uid">result> <result property="money" column="money">result> <association property="user" column="uid" select="com.cq.dao.UserDao.fingUser">association> resultMap> <select id="fingAccount" resultMap="accountMap"> select * from account select>
collection延迟加载
<resultMap id="userMap" type="user"> <id column="id" property="id">id> <result property="username" column="username">result> <result property="birthday" column="birthday">result> <result property="sex" column="sex">result> <result property="address" column="address">result> <collection property="list" column="id" select="com.cq.dao.AccountDao.fingAccount">collection> resultMap> <select id="fingUser" resultMap="userMap"> select * from user select>
public interface RoleDao { // 数据库的字段和实体字段冲突时,相当于手动映射 @Results( id = "roleMap", value = { @Result(id = true,property = "id",column = "id"), @Result(property = "roleName",column = "ROLE_NAME"), @Result(property = "roleDesc",column = "ROLE_DESC") } ) @Select("select * from role") public List<Role> fingAll(); public interface UserDao { @Select("select * from user") public List<User> findAll(); /** * 保存操作 * @param user * @return */ @Insert("insert into user(username,sex,birthday,address)values(#{username},#{sex},# {birthday},#{address})") @SelectKey(keyColumn="id",keyProperty="id",resultType=Integer.cl ass,before =false,statement = { "select last_insert_id()" }) int saveUser(User user); /** * 更新操作 * @param user * @return */ @Update("update user set username=#{username},address=# {address},sex=#{sex},birthday=#{birthday} where id =#{id} ") void updateUser(User user); /** * 删除用户 * @param userId * @return */ @Delete("delete from user where id = #{uid} ") void deleteUser(Integer userId); /** * 查询使用聚合函数 * @return */ @Select("select count(*) from user ") int findTotal(); }
mybatisplus是对原生的mybatis的增强,不影响原有的mybatis
引入依赖
<dependencies> <dependency> <groupId>com.baomidougroupId> <artifactId>mybatis-plusartifactId> <version>3.1.1version> dependency> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>5.1.47version> dependency> <dependency> <groupId>com.alibabagroupId> <artifactId>druidartifactId> <version>1.0.11version> dependency> <dependency> <groupId>org.projectlombokgroupId> <artifactId>lombokartifactId> <optional>trueoptional> <version>1.18.8version> dependency> <dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <version>4.12version> dependency> <dependency> <groupId>org.slf4jgroupId> <artifactId>slf4j-log4j12artifactId> <version>1.6.4version> dependency> dependencies>
mapper接口继承baseMapper
public interface UserMapper extends BaseMapper<User> { }
测试
public class UserTest { SqlSession sqlSession; UserMapper userMapper; @Before public void before()throws Exception{ String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(inputStream); sqlSession = sqlSessionFactory.openSession(); userMapper = sqlSession.getMapper(UserMapper.class); } //自带的单表crud @Test public void test02(){ // System.out.println(userMapper.selectById(1)); // List
list = new ArrayList // list.add(1); // list.add(2); // list.add(3); // List(); users = userMapper.selectBatchIds(list); // for (User user : users) { // System.out.println(user); // } Map<String,Object> map = new HashMap<String, Object>(); map.put("id","1"); map.put("name","张三"); List<User> users = userMapper.selectByMap(map); for (User user : users) { System.out.println(user); } } @Test public void test03()throws Exception{ User user = new User(6L,"厂长","123","赵云",32,"www.kenglidian.com"); // userMapper.insert(user); // sqlSession.commit(); } @Test public void test04()throws Exception{ // 方法1 // User user = new User(); // user.setPassword("abc"); // QueryWrapperwrapper = new QueryWrapper // wrapper.eq("id",1L); // int update = userMapper.update(user, wrapper); // System.out.println(update); // 方法2 UpdateWrapper<User> wrapper = new UpdateWrapper<User>(); wrapper.eq("id",6L).set("age",21); int update = userMapper.update(null, wrapper); sqlSession.commit(); } }();
环境
<dependencies> <dependency> <groupId>com.baomidougroupId> <artifactId>mybatis-plusartifactId> <version>3.1.1version> dependency> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>5.1.47version> dependency> <dependency> <groupId>com.alibabagroupId> <artifactId>druidartifactId> <version>1.0.11version> dependency> <dependency> <groupId>org.projectlombokgroupId> <artifactId>lombokartifactId> <optional>trueoptional> <version>1.18.4version> dependency> <dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <version>4.12version> dependency> <dependency> <groupId>org.slf4jgroupId> <artifactId>slf4j-log4j12artifactId> <version>1.6.4version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-contextartifactId> <version>5.3.20version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-jdbcartifactId> <version>5.2.0.RELEASEversion> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-testartifactId> <version>5.2.0.RELEASEversion> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-txartifactId> <version>5.2.0.RELEASEversion> dependency> dependencies>
定义spring的核心文件 applicationContext.xml,把mybatis的接口代理都交给spring容器管理
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3309/mybatisplus"/> <property name="password" value="root"/> <property name="username" value="root"/> bean> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource">property> <property name="configLocation" value="classpath:sqlMapConfig.xml">property> <property name="plugins"> <array> <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"> <property name="dialectType" value="mysql" /> bean> array> property> bean> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.cq.mapper">property> bean> beans>
mybatis的核心文件sqlMapConfig.xml
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <plugins> <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor"> <property name="maxTime" value="100" /> <property name="format" value="true" /> plugin> <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor">plugin> plugins> configuration>
测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class MyTest { @Autowired UserMapper userMapper; @Test public void test01() throws Exception{ User user = userMapper.fingId(1); System.out.println(user); } @Test public void test02()throws Exception{ List<User> users = userMapper.selectList(null); for (User user : users) { System.out.println(user); } } @Test public void test04(){ User user = new User(); List<User> users = user.selectAll(); for (User user1 : users) { System.out.println(user1); } } }
@TableName :关联数据库中的表
@TableId 我们可以在实体类的id属性上添加@TableId注解 id的增长策略
@TableField
@TableField注解可以指定字段的一些属性,常常解决的问题有2个:
1、对象中的属性名和字段名不一致的问题(非驼峰)
2、对象中的属性字段在表中不存在的问题 使用:
@Version:版本(乐观锁):
##2.5 mybatisplus的条件构造器
将条件封装到wrapper类中:QueryWrapper updateWrapper
当要更新一条记录的时候,希望这条记录没有被别人更新
有一个@Version注解
@Data @NoArgsConstructor @AllArgsConstructor @TableName("tb_user") public class User { @TableId(type = IdType.AUTO) private Long id; private String userName; private String password; private String name; private Integer age; private String email; @Version private Integer version; }
测试
@Autowired UserMapper **userMapper**; @Test public void testUpdate(){ User user = **new **User(); user.setAge(30); user.setId(2L); user.setVersion(1); *//获取到version为1* userMapper.updateById(user);
答案: 「day0607-homework」等文件 https://www.aliyundrive.com/s/tFvwv5Pmoar
点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。