Mybatis ——————mybatis 官方文档
==注意注意:增删改sql一定要committ(测试类) == 简单的增删改查操作CRUD 只需要改下面这三个方面就ok了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package com.kuang.utils.dao;import com.kuang.utils.eneity.User;import java.util.List;public interface UserMapper { List<User> findAllUser () ; User findUserbyid (int id) ; int addUser (User user) ; int updateUser (User user) ; int deleteUser (int id) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.kuang.utils.dao.UserMapper" > <select id ="findAllUser" resultType ="com.kuang.utils.eneity.User" > select * from day2021_9_6_studyMybatis_db.user </select > <select id ="findUserbyid" resultType ="com.kuang.utils.eneity.User" > select * from day2021_9_6_studyMybatis_db.user where id= #{id} </select > <insert id ="addUser" parameterType ="com.kuang.utils.eneity.User" > insert into day2021_9_6_studyMybatis_db.user(id,name,password)values (#{id},#{name},#{password}); </insert > <update id ="updateUser" parameterType ="com.kuang.utils.eneity.User" > update day2021_9_6_studyMybatis_db.user set name=#{name},password=#{password} where id=#{id}; </update > <update id ="deleteUser" parameterType ="_int" > delete from day2021_9_6_studyMybatis_db.user where id=#{id}; </update > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package com.kuang.utils.dao;import com.kuang.utils.eneity.User;import com.kuang.utils.mybatisutils;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.List;public class UserMapperTest { @Test public void testFindAllUser () { SqlSession sqlSession = mybatisutils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> allUser = userMapper.findAllUser(); for (User user : allUser) { System.out.println(user); } sqlSession.close(); } @Test public void testFindUserById () { SqlSession sqlSession = mybatisutils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User userbyid = mapper.findUserbyid(1 ); System.out.println(userbyid); sqlSession.close(); } @Test public void tsetaddUser () { SqlSession sqlSession = mybatisutils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.addUser(new User (6 ,"小刘" ,"1456" )); sqlSession.commit(); sqlSession.close(); } @Test public void tsetupdateUser () { SqlSession sqlSession = mybatisutils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.updateUser(new User (4 ,"小洋" ,"22456" )); sqlSession.commit(); sqlSession.close(); } @Test public void tsetdeleteUser () { SqlSession sqlSession = mybatisutils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.deleteUser(1 ); sqlSession.commit(); sqlSession.close(); } }
使用Map 上面在写sql语句的时候,由于参数或返回值要对应实体类;那么每次sql语句都要准确地对应实体类的属性;
万能的Map来了,那么每次写SQL语句的时候,就可以直接参数写map的键;(而且使用map的好处就是,键不能重复) ; 然后再实际调用的时候,再对map的键进行赋值
1 2 3 4 5 6 7 int allPowerfulMapToAdd (Map<String,Object> map) ;User allPowerfulMapToGet (Map<String,Object> map) ;
1 2 3 4 5 6 7 8 9 10 11 12 <insert id ="allPowerfulMapToAdd" parameterType ="map" > insert into day2021_9_6_studyMybatis_db.user(id,name,password)values (#{useId},#{Name},#{password}); </insert > <select id ="allPowerfulMapToGet" parameterType ="map" resultType ="com.xiaozhi.eneity.User" > select * from user where id= #{id} and name=#{name}; </select >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @Test public void testAddUserForMap () { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Object> map = new HashMap <String, Object>(); map.put("useId" ,7 ); map.put("Name" ,"小鸡战士" ); map.put("password" ,"55555" ); int i = mapper.allPowerfulMapToAdd(map); if (i>0 ){ System.out.println("添加数据条数=>" +i); } sqlSession.commit(); sqlSession.close(); } @Test public void testSelUserForMap () { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Object> map = new HashMap <String, Object>(); map.put("id" ,5 ); map.put("name" ,"特工" ); User user = mapper.allPowerfulMapToGet(map); System.out.println(user); sqlSession.commit(); sqlSession.close(); }
模糊查询 1 2 3 List<User> findUserByName (String name) ;
1 2 3 4 5 在UserMapper.xml中添加文件; <select id="findUserByName" resultType="com.xiaozhi.eneity.User" parameterType="String"> select * from user where name like #{name}; </select>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void testFindByName () { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userByName = mapper.findUserByName("%鱼%" ); for (User user : userByName) { System.out.println(user); } sqlSession.close(); }
1 2 3 4 5 6 <select id ="findUserByName" resultType ="com.xiaozhi.eneity.User" parameterType ="String" > select * from user where name like "%"#{name}"%"; </select >
配置优化学习 MyBatis 可以配置成适应多种环境,尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
比如说要写个别的环境;想要使用它,就把environments
标签的 default
指向那个环境.
transactionManager :事务管理器 ;有两种类型事务管理器 ([JDBC和MANAGED);默认使用JDBC; 这个MANAGED不常用;
dataSource 数据源 ;用于连接数据库 .
有三种数据源:
UNPOOLED不使用数据库连接池;
POOLED (默认) 使用数据库连接池;
JNDI应用服务器类使用;
属性优化(properties) 还记着之前使用连接池时,读取properties文件的配置;还是比较方便的;数据库连接池学习—DBCP;C3P0连接池
可以在resources
目录下编写db.properties
文件
在核心配置文件mybatis-config.xml配置文件中(引入)数据源;注意properties标签要写在核心配置文件的首位; 在环境标签下的dataSource下就能获取到了;就像之前那个el表达式的格式一样;${属性名} 就可读取到了;而且,由于配置文件是写在外部的,可以动态修改;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?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" /> <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="${driver}" /> <property name ="url" value ="${url}" /> <property name ="username" value ="${username}" /> <property name ="password" value ="${password}" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="com/xiaozhi/dao/UserMapper.xml" /> </mappers > </configuration >
还可以在标签体添加属性 ;有时可能外部配置文件中的属性要被其他的文件读取;那么把这些属性写在外部配置文件就不合适;将这个文件需要的属性添加到properties
的标签体即可;
1 2 3 4 <properties resource ="db.properties" > <property name ="password" value ="13245" /> <property name ="df" value ="deqwq" /> </properties >
需要注意的是:当外部配置文件和properties内定义的属性出现重名的情况;默认优先使用的是引入的外部文件内容!!!
别名优化(typeAliases) 使用别名可以减少代码的冗余,看起来也比较清晰明了
注意IDEA给出的提示,标签不能乱放位置
1 2 3 4 5 <typeAliases > <typeAlias type ="com.kuang.utils.eneity.User" alias ="User" /> </typeAliases >
也可以指定一个包名,mybatis会自动将这个包的实体类的类名定义为他的默认别名,首字母小写!
比如说配置扫描存放实例类User的包eneity;那么User类的别名就是user
1 2 3 4 <typeAliases > <package name ="com.kuang.utils.eneity" /> </typeAliases >
==实体类较少用第一种(可以DIY别名) 实体类较多用第二种 ==
在使用扫描包的方式(第二种);之后
;如果不想用默认的小写开头的别名,还可以直接在实体类使用注解的方式; 比如说在**实体类User 上面使用注解****@Alias("别名")**
注意导包为import org.apache.ibatis.type.Alias
.
1 2 3 4 5 import org.apache.ibatis.type.Alias;@Alias("myUser")
设置(settings)–了解 需要注意的几个;
mapUnderscoreToCamelCase
1 2 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 默认为false 关闭状态的;
比如说在数据库写了个字段名为 res_time;然后在java实体类里面用的是驼峰命名法resTime;把这个属性一设置,它就能成功映射到对应的属性了;
logImpl ; 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
1 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
在下半部分会用到日志;
cacheEnabled :全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。默认是开启的;lazyLoadingEnabled 懒加载的全局开关。开启后所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。
映射器(mappers) ==注意:not known to the MapperRegistry.它说没有找到mapper映射可能是pom.xml maven依赖那里build没有配置rescourse ==
之前刚开始配好mybatis后,运行测试代码;出现的mapper映射问题;
1 org.apache.ibatis.binding.BindingException: Type interface com .xiaozhi.dao.UserDao is not known to the MapperRegistry.
MapperRegistry :注册绑定mapper文件;
需要在核心配置文件mybatis-config.xml,把UserMapper.xml添加注册;
主要有三种方式配置mapper:
==(1)使用相对于类路径的资源引用;(最推荐使用 首选) ==
1 2 3 <mappers > <mapper resource ="com/kuang/utils/dao/UserMapper.xml" /> </mappers >
(2)使用映射器接口实现类的完全限定类名 (了解)
但使用这种方式有时可能会出错; 错误一:如果说把Mapper.xml配置文件放在了别的包下;会出现找不到mapper的错误; 错误二:例如说有时候不注意把接口命名为UserDao;而映射文件还是UserMapper.xml,这也会出现找不到mapper的情况. name怎么避免呢?==> 保证接口和xml配置文件在同一个包下;且是同名的.
1 2 3 <mappers > <mapper class ="com.xiaozhi.dao.UserMapper" /> </mappers >
(3)进行包扫描 ;将包下的所有映射器接口实现注册;**(了解) 包扫描时也要保证接口和xml配置文件在同一个包下;且是同名的.
1 2 3 <mappers > <package name ="com.xiaozhi.dao.UserMapper" /> </mappers >
生命周期,作用域 生命周期与作用域使用不当会导致并发问题;
SqlSessionFactoryBuilder在 创建sqlsessionfactory后就不需要了;
SqlSessionFactory;可以理解为一个数据库连接池 ; 被创建就应在应用的运行期一直存在,不需要销毁或重新创建实例。适用于应用作用域,可使用单例模式或者静态单例模式.
SqlSession 是连接到数据库的一个请求 ,它的实例不是线程安全的,所以无法被共享,作用于请求或方法的作用域;用完就关闭,防止资源浪费. SqlSession可以去对应多个映射.
ResultMap 结果集映射 (如果实体类的属性和数据库的字段名不一致——–执行根据Id查询的方法;查询出的姓名为null,空值;
解决方式一:在SQL查询语句使用别名;
1 2 3 4 <!--解决方式1:在sql字段使用别名--> <select id="findUserById" resultType="myUser" parameterType="_int"> select id,name as username,password from user where id= #{id}; </select>
解决方式二: 通过结果集映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <resultMap id ="UserMap" type ="myUser" > <result property ="id" column ="id" /> <result property ="username" column ="name" /> <result property ="password" column ="password" /> </resultMap > <select id ="findUserById" resultMap ="UserMap" parameterType ="_int" > select * from user where id= #{id}; </select >
日志 在运行项目的时候,出现异常就需要依次排除错误,以前常用的System.out控制台输出或者debug调试显然是比较麻烦的;
使用日志无疑是一个比较好的方式.
SLF4J
Apache Commons Logging
Log4j 2
Log4j 【掌握】
JDK logging
STDOUT_LOGGING【掌握】
9.1使用标准日志工厂 ==注意,setting中设置日志时,name必须为logImpl; ==
比如说,使用标准 日志 STDOUT_LOGGING在mybatis-config.xml中设置开启日志;
1 2 3 <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings >
测试执行根据Id查询的方法;
log4j 日志 可以控制打印的日志输出位置;控制台,文件或者GUI组件; 可控制输出格式;可定义日志的级别;可在配置文件中单独配置.
先把log4j的包导入到项目中; 在pom.xml
配置文件导入依赖;这里用的是log4j-1.2.17版本
1 2 3 4 5 6 <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > 1.2.17</version > </dependency >
在resources目录
下创建log4j.properties
资源文件;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 log4j.rootLogger =DEBUG,console,file log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold =DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern =[%c]-%m%n log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File =./log/xiaozhi.log log4j.appender.file.MaxFileSize =10mb log4j.appender.file.Threshold =DEBUG log4j.appender.file.layout =org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern =[%p][%d{yy-MM-dd}][%c]%m%n log4j.logger.org.mybatis =DEBUG log4j.logger.java.sql =DEBUG log4j.logger.java.sql.Statement =DEBUG log4j.logger.java.sql.ResultSet =DEBUG log4j.logger.java.sql.PreparedStatement =DEBUG
在mybatis-config.xml
设置日志;
1 2 3 <settings > <setting name ="logImpl" value ="LOG4J" /> </settings >
测试运行;比之前的标准日志更详细;
使用 在需要使用log4j的类;导入包;
import org.apache.log4j.Logger; 创建日志对象;参数为当前类的class;
1 static Logger logger= Logger.getLogger(UserDaoTest.class);
尝试在测试类中创建一个方法;调用日志方法;
1 2 3 4 5 6 7 @Test public void testForLog () { logger.info("info:info信息==>" ); logger.debug("debug:debug调试==>" ); logger.error("error:异常==>" ); }
分页 1.直接在SQL语句中用limit分页,然后传参.(常用) 在UserMapper
中定义方法;
1 2 List<User> findUserToLimit (Map<String ,Integer> map) ;
在UserMapper.xml
中写sql语句;
1 2 3 4 5 6 7 <resultMap id ="UserMap" type ="user" > </resultMap > <select id ="findUserToLimit" parameterType ="map" resultMap ="UserMap" > select * from day2021_9_6_studyMybatis_db.user limit #{startpage},#{pageSize}; </select >
测试使用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void testLimit () { SqlSession sqlSession=mybatisutils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String ,Integer> map=new HashMap <String ,Integer>(); map.put("startpage" ,0 ); map.put("pageSize" ,5 ); List<User> userToLimit = mapper.findUserToLimit(map); for (User user : userToLimit) { System.out.println(user); } sqlSession.close(); }
2.使用 RowBounds分页(了解) 在UserMapper
定义方法;
1 2 List<User> findUserRowBounds () ;
在UserMapper.xml
中写sql语句,sql语句不写分页
1 2 3 4 <select id ="findUserRowBounds" resultMap ="UserMap" > select * from uday2021_9_6_studyMybatis_db.userr </select >
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void testRowBounds () { SqlSession sqlSession=MybatisUtils.getSqlSession(); RowBounds rowBounds = new RowBounds (5 ,5 ); List<User> selectList=sqlSession.selectList("com.kuang.utils.dao.UserMapper.findUserRowBounds" ,null ,rowBounds); for (User user : selectList) { System.out.println(user); } sqlSession.close(); }
3.分页插件PageHelpe(大项目可能才用) https://pagehelper.github.io/
使用注解开发(简单的sql语句比较好用,复杂的就比较麻烦) 首先整个设置是面向接口编写程序的.
在UserMapper
接口的定义方法处直接使用注解;放入SQL语句;
1 2 3 4 @Select("select * from day2021_9_6_studyMybatis_db.user where id=#{id} and name=#{name}") User findUserById (@Param("id") int id, @Param("name") String name) ;
需要在mybatis-config.xml
中绑定接口;
1 2 3 4 <mappers > <mapper class ="com.kuang.utils.dao.UserMapper" /> </mappers >
在测试时,其实已经通过反射得到接口的定义方法返回值
本质:反射机制实现
底层:动态代理模式
1 2 3 4 5 6 7 8 9 10 @Test public void testFindUserById () { SqlSession sqlSession = mybatisutils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.findUserById(2 , "杰哥" ); System.out.println(user); sqlSession.close(); }
Mybatis开发的流程 (底层–面试前看)——了解把之前写的工具类详细看看;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory=null ; static { try { String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder ().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession () { SqlSession sqlSession = sqlSessionFactory.openSession(); return sqlSession; } }
首先是由==Resources
==获取且加载全局的配置文件,然后是实例化==SqlSessionFactoryBuilder
==; 点进build方法的源码; 里面是==创建XMLConfigBuilder
==来解析配置文件流的;
接着是==Configuration==传入所有的配置文件信息;
实例化==sqlSessionFactory==; 先通过事务管理==transaction==; 然后创建==executor器==;
创建==sqlSession== ==>实现增删改查;如果出了问题,就需要事务回滚,回到事务管理;
若执行成功,提交事务;关闭资源.
在写工具类的时候,使用方法openSession() 来获取sqlSession;
进入源码查看;该方法有很多重载的;注意到有个以布尔值为参数的方法;查看它的实现;
SqlSession openSession(boolean var1);
是否开启自动提交事务;
1 2 3 public SqlSession openSession (boolean autoCommit) { return this .openSessionFromDataSource(this .configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null , autoCommit); }
然后呢,在工具类获取sqlSession的时候,给openSession()传入参数true;
也就是自动提交事务;那么就不用commit手动提交事务;
1 2 3 4 5 public static SqlSession getSqlSession () { SqlSession sqlSession = sqlSessionFactory.openSession(true ); return sqlSession; }
用注解完成一个添加方法; 在UserMapper
定义方法;且用注解完成sql语句;
1 2 3 @Insert("insert into day2021_9_6_studyMybatis_db.user values(#{id},#{name},#{password})") void addUser (User user) ;
在mybatis-config.xml
上面已经绑定过UserMapper了, 测试即可,无需手动提交事务;
1 2 3 4 5 6 7 8 9 10 @Test public void testAddUser () { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.addUser(new User (13 ,"蕉宝" ,"846662" )); sqlSession.close(); }
==扩展小知识,在写sql语句时,#{}可防止sql注入
, ${}
无法防止sql注入; ==
Lombok插件的使用(偷懒可用——省去写实体类的步骤)
1 2 3 4 5 6 7 <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.20</version > </dependency >
使用@Data
注解;生成无参构造,get,set方法,equals方法,hashCode方法,toString方法.
注解@AllArgsConstructor
生成有参构造方法
注解@NoArgsConstructor
生成无参构造方法
注解@ToString
生成toString方法; 注解@EqualsAndHashCode
生成equals方法和hashCode方法
注解@Getter
,注解@Setter
放在类上,生成所有非静态的属性get,set方法; 放在属性上,仅生成该属性的get,set方法.
多对一情况 按照类似子查询的方式, 查询语句嵌套 那么先把这个问题拆分开来; 用两段SQL语句; 先查询学生,再根据Id查询教师表;
在写sql之前;需要了解结果集Map映射 ==association 是表示对象; collection表示集合. javaType;表示指定属性的类型;一般来说,在集合中的泛型类型用ofType指定==
==property 需要映射到JavaBean 的属性名称**(就是数据库表中的字段)。 column 数据表的列名或者标签别名 (就是要映射的名字或者是自己定义的别名)**。 javaType 一个完整的类名,或者是一个类型别名。如果你匹配的是一个JavaBean,那MyBatis 通常会自行检测到。然后,如果你是要映射到一个HashMap,那你需要指定javaType 要达到的目的。==
==jdbcType 数据表支持的类型列表。这个属性只在insert,update 或delete 的时候针对允许空的列有用。JDBC 需要这项,但MyBatis 不需要。如果你是直接针对JDBC 编码,且有允许空的列,而你要指定这项。 typeHandler 使用这个属性可以覆写类型处理器。这项值可以是一个完整的类名,也可以是一个类型别名。==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <select id ="finAllStudent" resultMap ="studentMap" > </select > <resultMap id ="studentMap" type ="student" > <result property ="id" column ="id" /> <result property ="name" column ="name" /> <association property ="teacher" column ="tid" javaType ="teacher" select ="findTeacherById" /> </resultMap > <select id ="findTeacherById" resultType ="teacher" > select * from teacher where id=#{tid}; </select >
查询结果嵌套(推荐使用) 在查询的结果集类型中将教师属性关联;
1 2 3 4 5 6 7 8 9 10 11 12 13 <resultMap id ="studentteacher" type ="Student" > <result property ="id" column ="sid" /> <result property ="name" column ="sname" /> <association property ="teacher" javaType ="Teacher" > <result property ="name" column ="tname" /> </association > </resultMap > <select id ="finAllStudent" resultMap ="studentteacher" > select s.id sid,s.name sname,t.name tname from student s ,teacher t where s.tid=t.id; </select >
一对多情况 按照查询嵌套处理(了解) ——可以理解是通过子查询来实现的,需要写两个查询语句查两张表(通过查到teacher中teacherid来查student的所有id成员)
这种查询需要写javatype——对应实体类的需求类型 collection后要关系到另一个select语句就用column字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <select id ="findStuByTeaId" resultMap ="TeacherMap2" > select * from teacher where id=#{tid}; </select > <resultMap id ="TeacherMap2" type ="teacher" > <result column ="id" property ="id" /> <result column ="name" property ="name" /> <collection property ="students" javaType ="ArrayList" ofType ="student" column ="id" select ="findStuById" /> </resultMap > <select id ="findStuById" resultType ="student" > select * from student where tid=#{tid}; </select >
按照结果嵌套查询(主要使用) 这种就是通过查出目的实体类中有什么属性然后查询并一一映射对应
然后collection或者association中展开相关实体类要查的属性查询并一一映射对应
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <select id ="findStuByTeaId" resultMap ="TeacherMap" > select s.name sname , s.id sid ,t.id tid , t.name tname from teacher t,student s where t.id=s.tid and tid=#{tid} </select > <resultMap id ="TeacherMap" type ="teacher" > <result property ="id" column ="tid" /> <result property ="name" column ="tname" /> <collection property ="students" ofType ="student" > <result property ="id" column ="sid" /> <result property ="name" column ="sname" /> <result property ="tid" column ="tid" /> </collection > </resultMap >
两种对应情况总结 ==@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中(一般通过#{}的方式,${}会有sql注入的问题)==
==ofType表示的是映射到集合中的的泛型(实体类)类型——比如一对多中list集合中的类型—— ofType=”student”==
动态sql环境搭建(看idea—untitled3) —动态sql只是我们可以在sql层面去执行一个逻辑代码 多了一个idutils类 其他环境基本不变——resourses,pom依赖整体大部分不变
接口及其xml要变—并且在mappers中注册,接口的xml的namespace要改
==UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分==
==UUID通用唯一标识符 randomUUID()唯一的通用唯一标识符==
1 2 3 4 5 6 7 public class IdUtils { public static String getId () { return UUID.randomUUID().toString().replaceAll("-" ,"" ); } }
==对于的实体类中属性createTime
和数据库名的字段create_time
命名不一致,可在**mybatis的核心配置文件**
中更改settings设置为开启驼峰命名自动转换.==
==mapUnderscoreToCamelCase
是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。==
动态SQL –>IF标签使用 ——好处是直接在测试类中添加约束属性就行
现在接口定义方法
在BlogMapper.xml中
编写sql语句; 注意会用到if判断(if text是必须后面加条件);前面的 1=1
防止后面的条件若都不符合就查询输出所有的数据;
只要对需要查询的输入对应参数即可进行查询;不用去手动改变SQL语句;
if语句可以多次出现,也就是可以进行多重if判断
1 2 3 4 5 6 7 8 9 10 11 12 13 <select id ="findBlogHaveIf" resultType ="blog" parameterType ="map" > select * from blog where 1=1 <if test ="title!=null" > and title =#{title} </if > <if test ="author !=null" > and author =#{author} </if > <if test ="views != null" > and views =#{views} </if > </select >
1 2 3 4 5 6 7 8 9 10 11 @Test public void testFindBlogHaveIf () { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map=new HashMap (); List<Blog> blogs = mapper.findBlogHaveIf(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
若在执行时,对title属性进行赋值;就要查询这个指定的属性对应结果;只需在测试执行时添加;查询结果 ;它会自动地调整SQL语句.
动态SQL的常用标签 where 标签;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <select id ="findBlogHaveIf" resultType ="blog" parameterType ="map" > select * from blog <where > <if test ="title!=null" > title =#{title} </if > <if test ="author !=null" > and author =#{author} </if > <if test ="views != null" > and views =#{views} </if > </where > </select >
测试结果:
==什么条件参数也不传入,执行时,确实没有出现where==
==再通过条件浏览量 views
去查询;注意看看它是否会去掉前面的 and
——————确实自动去掉了and
==
choose (when, otherwise)标签 ==若有多个条件,可选择其中的一个,类似于java的判断switch语句.
otherwise
其他条件==
==还是查询方法;不过这次用choose进行判断过滤==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <select id ="findBlogByChoose" resultType ="blog" parameterType ="map" > select * from blog <where > <choose > <when test ="title != null" > title=#{title} </when > <when test ="author !=null" > and author =#{author} </when > <otherwise > and views =#{views} </otherwise > </choose > </where > </select >
==如果输入title,author,views三个参数进行查询;——只会执行xml中第一个写的if参数(上面先写title是title只会查出title)作为条件==
set标签 set 标签可动态地在行首插入 SET 关键字,删掉额外的逗号
1 2 3 4 5 6 7 8 9 10 11 12 <update id ="updateBlogBySet" parameterType ="map" > update blog <set > <if test ="title !=null" > title= #{title}, </if > <if test ="author !=null" > author= #{author}, </if > </set > where id=#{id} </update >
注意执行时,它自动去掉了 author 后的逗号
1 2 3 4 5 6 7 8 9 10 11 @Test public void testUpdateBlogBySet () { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map=new HashMap (); map.put("title" ,"关于转生那件事" ); map.put("author" ,"阿猫" ); map.put("id" ,"7de2fa32bb1f42649bbe3d04e2afd796" ); mapper.updateBlogBySet(map); sqlSession.close(); }
sql片段 SQL片段也就是把一些公用的SQL语句提取出来;方便使用;避免代码冗余.
可使用 标签中写入公用的SQL语句;然后用 标签去引用; 标签 的refid 对应 标签的id;
建议不要将复杂SQL作为SQL片段.
比如说,在查询方法的SQL语句中,提取出SQL片段;用inclued标签引入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <select id ="findBlogHaveIf" resultType ="blog" parameterType ="map" > select * from blog <where > <include refid ="isPublicCode" > </include > </where > </select > <sql id ="isPublicCode" > <if test ="title!=null" > title =#{title} </if > <if test ="author !=null" > and author =#{author} </if > <if test ="views != null" > and views =#{views} </if > </sql >
动态SQL之foreach标签.
遍历时,==遍历的是一个集合,索引为index
, **每次遍历取出的元素就是 item**
; 用open
表示开头 ;close
表示结尾;使用separator
作为分隔符==,将 SQL语句拼接起来.
当collection是列表的时候 item代表列表中的元素 index代表正在迭代的下标
当collection是映射的时候 item代表的是value index代表key open代表了迭代最开始的符号 separator代表了每一个迭代元素之间的分割符号 close代表了结束符号
当collection也可以是map
1 2 3 4 5 6 7 8 9 10 <select id ="findBlogForEach" resultType ="blog" parameterType ="map" > select * from blog <where > <foreach collection ="allId" item ="id" open ="and (" separator ="or" close =")" > id=#{id} </foreach > </where > </select >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void testFindBlogForEach () { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map=new HashMap (); List<Integer> list=new ArrayList <Integer>(); list.add(1 ); list.add(3 ); map.put("allId" ,list); List<Blog> blogForEach = mapper.findBlogForEach(map); for (Blog blog : blogForEach) { System.out.println(blog); } sqlSession.close(); }
Mybatis缓存–自行了解