MyBatis 是一个对JDBC的封装,是一个数据持久化框架
优点 减少代码量,降低维护成本,讲SQL写到XML中,降低耦合度,支持动态SQL语句,支持标签映射,
缺点 SQL编写工作量大,SQL语句依赖数据库,导致移植性较差
核心接口和类 SqlSessionFactoryBuilder - SqlSessionFactory - SqlSession
开发方式 使用原生接口或者用Mapper代理实现自定义接口
实际操作
1 2 3 4 5 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.4.5</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <build > <resources > <resource > <directory > src/main/resources</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > <resource > <directory > src/main/java</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > </resources > </build >
创建表
创建表对应的实体类
创建MyBatis配置文件MyBatis.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" > </property > <property name ="url" value ="jdbc:mysql://localhost:3306/mybatis?useUnicode=true& characterEncoding=UTF-8" > </property > <property name ="username" value ="root" > </property > <property name ="password" value ="123456" > </property > </dataSource > </environment > <environment id ="other" > </environment > </environments >
创建Mapper.xml namespace 设置为文件所在包+文件名,insert表示执行insert,id是参数,parameterType是类型1 2 3 4 5 6 7 8 9 <?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.wsx.mapper.AccoutMapper" > <insert id ="save" parameterType ="com.wsx.entity.Account" > insert into t_account(username,password,age) values(#{username},#{password},#{age}) </insert > </mapper >
注册SQL语句1 2 3 4 5 6 7 8 9 <mappers > <mapper resource ="com/wsx/mapper/AccountMapper.xml" > </mapper > <mapper resource ="com/wsx/repository/AccountRepository.xml" > </mapper > <mapper resource ="com/wsx/repository/StudentRepository.xml" > </mapper > <mapper resource ="com/wsx/repository/ClassesRepository.xml" /> <mapper resource ="com/wsx/repository/CustomerRepository.xml" /> <mapper resource ="com/wsx/repository/GoodsRepository.xml" /> </mappers >
调用接口
1 2 3 4 5 6 7 8 9 10 InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml" );SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder ();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();String statement = "com.wsx.mapper.AccoutMapper.save" ;Account account = new Account (1L ,"张三" ,"123123" ,22 );sqlSession.insert(statement,account); sqlSession.commit(); sqlSession.close();
自定义接口 1 2 3 public interface AccountRepository { public int save (Account account) ; public int update (Account account) ;
1 2 3 4 5 6 <insert id ="save" parameterType ="com.wsx.entity.Account" > insert into t_account(username,password,age) values(#{username},#{password},#{age}) </insert > <update id ="update" parameterType ="com.wsx.entity.Account" > update t_account set username = #{username},password = #{password},age = #{age} where id = #{id} </update >
1 2 3 4 5 6 7 InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml" );SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder ();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();AccountRepository accountRepository = sqlSession.getMapper(AccountRepository.class);accountRepository.()
传入多个变量 1 2 3 <select id ="findByNameAndAge" resultType ="com.wsx.entity.Account" > select * from t_account where username = #{arg0} and age = #{arg1} </select >
查询深入 多对一 比方这个, 我们查询出来有多个id,这时候,student对象的id会匹配第一个,name也是,所以查询出来classes就null了 我们需要使用resultMap来处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Data public class Classes { private long id; private String name; private List<Student> students; } @Data public class Student { private long id; private String name; private Classes classes; }
1 2 3 4 5 6 7 8 9 10 11 12 <resultMap id ="studentMap" type ="com.wsx.entity.Student" > <id column ="id" property ="id" > </id > <result column ="name" property ="name" > </result > <association property ="classes" javaType ="com.wsx.entity.Classes" > <id column ="cid" property ="id" > </id > <result column ="cname" property ="name" > </result > </association > </resultMap > <select id ="findById" parameterType ="long" resultMap ="studentMap" > select s.id,s.name,c.id as cid,c.name as cname from student s,classes c where s.id = #{id} and s.cid = c.id </select >
一对多 1 2 3 4 5 6 7 8 9 10 11 12 <resultMap id ="classesMap" type ="com.wsx.entity.Classes" > <id column ="cid" property ="id" > </id > <result column ="cname" property ="name" > </result > <collection property ="students" ofType ="com.wsx.entity.Student" > <id column ="id" property ="id" /> <result column ="name" property ="name" /> </collection > </resultMap > <select id ="findById" parameterType ="long" resultMap ="classesMap" > select s.id,s.name,c.id as cid,c.name as cname from student s,classes c where c.id = #{id} and s.cid = c.id </select >
逆向工程 传统开发中,实体类、自定义Mapper接口、Mapper.xml 需要开发者手动创建,逆向工程可以帮助开发者来自动创建三个组件,减少工作量
MBG MyBatis Generator , 一个专门为MyBatis框架开发者定制的代码生成器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.4.5</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.11</version > </dependency > <dependency > <groupId > org.mybatis.generator</groupId > <artifactId > mybatis-generator-core</artifactId > <version > 1.3.2</version > </dependency >
配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration > <context id ="testTables" targetRuntime ="MyBatis3" > <jdbcConnection driverClass ="com.mysql.cj.jdbc.Driver" connectionURL ="jdbc:mysql://localhost:3306/mybatis?useUnicode=true& characterEncoding=UTF-8" userId ="root" password ="123456" > </jdbcConnection > <javaModelGenerator targetPackage ="com.wsx.entity" targetProject ="./src/main/java" > </javaModelGenerator > <sqlMapGenerator targetPackage ="com.wsx.repository" targetProject ="./src/main/java" > </sqlMapGenerator > <javaClientGenerator type ="XMLMAPPER" targetPackage ="com.wsx.repository" targetProject ="./src/main/java" > </javaClientGenerator > <table tableName ="t_user" domainObjectName ="User" > </table > </context > </generatorConfiguration >
1、jdbcConnection 配置数据库连接信息。 2、javaModelGenerator 配置 JavaBean 的⽣成策略。 3、sqlMapGenerator 配置 SQL 映射⽂件⽣成策略。 4、javaClientGenerator 配置 Mapper 接⼝的⽣成策略。 5、table 配置⽬标数据表(tableName:表名,domainObjectName:JavaBean 类名)。 生成代码如下,这个代码不重要,跑就完事了, 他就给我们生成了很多sql
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 List<String> warings = new ArrayList <String>(); boolean overwrite = true ;String genCig = "/generatorConfig.xml" ;File configFile = new File (Main.class.getResource(genCig).getFile());ConfigurationParser configurationParser = new ConfigurationParser (warings);Configuration configuration = null ;try { configuration = configurationParser.parseConfiguration(configFile); } catch (IOException e) { e.printStackTrace(); } catch (XMLParserException e) { e.printStackTrace(); } DefaultShellCallback callback = new DefaultShellCallback (overwrite);MyBatisGenerator myBatisGenerator = null ;try { myBatisGenerator = new MyBatisGenerator (configuration,callback,warings); } catch (InvalidConfigurationException e) { e.printStackTrace(); } try { myBatisGenerator.generate(null ); } catch (SQLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); }
延迟加载 先配置
1 2 3 4 5 6 <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> <setting name ="lazyLoadingEnabled" value ="true" /> </settings >
然后把多表关联查询拆分成多个单表查询, 调用接口的时候再去查询,不用就不查询,比方有图书表和图书类型表,我们查到了一些类型,这就是一个单表查询,如果你不去调用getBook,接下来的查询就不会进行, 慎用,这个东西讲一次查询拆成了多次,这可能导致性能降低
MyBatis缓存 我干嘛不用redis?
一级缓存 默认开启且不可关闭,是SqlSession级别的,用HashMap实现,不同的SqlSession之间的数据区域互不影响, 当执行了DML操作(insert,update,delete),就要清空缓存
二级缓存 多个SqlSession共用同一个缓存,依然是HashMap实现 在config.xml中开启
1 2 3 4 5 6 7 8 <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> <setting name ="lazyLoadingEnabled" value ="true" /> <setting name ="cacheEnabled" value ="true" /> </settings >
在Mapper.xml 中加入
实体类要实现序列化(Serializable)
第三方缓存 1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-ehcache</artifactId > <version > 1.0.0</version > </dependency > <dependency > <groupId > net.sf.ehcache</groupId > <artifactId > ehcache-core</artifactId > <version > 2.4.3</version > </dependency >
配置第三方缓存,ehcache.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <ehcache xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation ="../config/ehcache.xsd" > <diskStore /> <defaultCache maxElementsInMemory ="1000" maxElementsOnDisk ="10000000" eternal ="false" overflowToDisk ="false" timeToIdleSeconds ="120" timeToLiveSeconds ="120" diskExpiryThreadIntervalSeconds ="120" memoryStoreEvictionPolicy ="LRU" > </defaultCache > </ehcache >
在config.xml中开启(同上) 最后在mapper.xml中配置 缓存失效间隔、回收策略, 这里就不需要实现序列化了
1 2 3 4 5 6 7 8 <cache type ="org.mybatis.caches.ehcache.EhcacheCache" > <property name ="timeToIdleSeconds" value ="3600" /> <property name ="timeToLiveSeconds" value ="3600" /> <property name ="memoryStoreEvictionPolicy" value ="LRU" /> </cache >
动态SQL where 控制 and是否删除, if 控制是否存在, 这里我不深入了…会用就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <select id ="findByAccount" parameterType ="com.wsx.entity.Account" resultType ="com.wsx.entity.Account" > select * from t_account <where > <if test ="id!=0" > id = #{id} </if > <if test ="username!=null" > and username = #{username} </if > <if test ="password!=null" > and password = #{password} </if > <if test ="age!=0" > and age = #{age} </if > </where > </select >
参考资料 4小时学会MyBatis 你真的懂了mybatis延迟加载吗?