1) MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
2) MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
3) MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects, 普通的Java对象)
映射成数据库中的记录
下载地址: mybatis/mybatis-3: MyBatis SQL mapper framework for Java (github.com)
JDBC
Hibernate 和 JPA
MyBatis
<dependencies> <!-- Mybatis核心 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <!-- junit测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.3</version> </dependency> </dependencies>
配置文件习惯上命名为mybatis-config.xml,核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--设置连接数据库的环境--> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!--引入映射文件--> <mappers> <mapper resource="mappers/UserMapper.xml"/> </mappers> </configuration>
MyBatis中的mapper接口相当于以前的dao.但是区别在于,mapper仅仅是接口,我们不需要提供实现类.
public interface UserMapper { /** * 添加用户信息 */ int insertUser(); }
相关概念: ORM(Object Relationship Mapping) 对象关系映射
Java概念 | 数据库概念 |
---|---|
类 | 表 |
属性 | 字段/列 |
对象 | 记录/行 |
1、映射文件的命名规则: 表所对应的实体类的类名+Mapper.xml
例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml
因此一个映射文件对应一个实体类,对应一张表的操作
MyBatis映射文件用于编写SQL,访问以及操作表中的数据
MyBatis映射文件存放的位置是src/main/resources/mappers目录下
2、MyBatis中可以面向接口操作数据,要保证两个一致:
a>mapper接口的全类名和映射文件的命名空间(namespace)保持一致
b>mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致
public class MyBatisTest { /** * SqlSession默认不自动提交事务,若需要自动提交事务 * 可以使用sqlSessionFactory.openSession(ture); * @throws IOException */ @Test public void testMyBatis() throws IOException { //加载核心配置文件 InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); //获取SqlSessionFactoryBuilder SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //获取sqlSessionFactory SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is); //获取SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(true); //获取mapper接口对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //测试功能 int result = userMapper.insertUser(); //提交事务 // sqlSession.commit(); System.out.println("result = " + result); } }
<!-- log4j日志 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender"> <param name="Encoding" value="UTF-8" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" /> </layout> </appender> <logger name="java.sql"> <level value="debug" /> </logger> <logger name="org.apache.ibatis"> <level value="info" /> </logger> <root> <level value="debug" /> <appender-ref ref="STDOUT" /> </root> </log4j:configuration>
日志的级别
FATAL(致命)>ERROR(错误)>WARN(错误)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越详细
MyBatis核心配置文件中,标签的顺序
properties?,settings?,typeAliases?,typeHandlers?,
objectFactory?,objectWrapperFactory?,reflectorFactory?,
plugins?,environments?,databaseIdProvider?,mappers?".
<?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> <!-- MyBatis核心配置文件中,标签的顺序 properties?,settings?,typeAliases?,typeHandlers?, objectFactory?,objectWrapperFactory?,reflectorFactory?, plugins?,environments?,databaseIdProvider?,mappers?". --> <!--引入properties文件--> <properties resource="jdbc.properties"/> <!--设置类型别名--> <typeAliases> <!-- typeAlias: 设置某个类型的别名 属性: type: 设置需要设置别名的类型 alias: 设置某个类型的别名,若不设置该属性,那么该类型拥有默认的别名,即类名且不区分大小写 --> <typeAlias type="com.learning.mybatis.pojo.User" alias="User"></typeAlias> <!--以包为单位, 将包下所有的类型设置默认的类型别名,即类名且不区分大小写--> <package name="com.learning.mybatis.pojo"/> </typeAliases> <!-- environments: 配置多个连接数据库的环境 属性: default: 设置默认使用环境的id --> <environments default="development"> <!-- environment: 配置某个具体的环境 属性: id: 表示连接数据库的环境的唯一标识,不能重复 --> <environment id="development"> <!-- transactionManager: 配置事务管理方式> 属性: type="JDBC/MANAGED" JDBC: 表示当前环境中, 执行SQL时, 使用的是JDBC中原生的事务管理方式,事务的提交或回滚需要手动处理 MANAGED: 被管理,例如Spring --> <transactionManager type="JDBC"/> <!-- dataSource: 配置数据源 属性: type: 设置数据源的类型 type="POOLED/UNPOOLED/JNDI" POOLED: 表示使用数据库连接池缓存数据库连接 UNPOOLED: 表示不使用数据库连接池 JNDI: 表示使用上下文中的数据源 --> <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> <!--<mapper resource="mappers/UserMapper.xml"/>--> <!-- 以包为单位引入映射文件 要求: 1、mapper接口所在的包要和映射文件所在的包一致 2、mapper接口要和映射文件的名字一致 --> <package name="com.learning.mybatis.mapper"/> </mappers> </configuration>
1、添加
<!--int insertUser();--> <insert id="insertUser"> insert into t_user values (null, '嘉然', '123', 18, '女', '12345@qq.com') </insert>
2、删除
<!--int deleteUser();--> <delete id="deleteUser"> delete from t_user where id = 6 </delete>
3、修改
<!--void updateUser()--> <update id="updateUser"> update t_user set username = '张三' where id = 1 </update>
4、查询一个实体类对象
<!--User getUserById();--> <!-- 查询功能的标签必须设置resultType或resultMap --> <select id="getUserById" resultType="User"> select * from t_user where id = 3; </select>
5、查询集合
<!--List<User> getAllUser();--> <select id="getAllUser" resultType="User"> select * from t_user </select>
注意:
1、查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射 关系
resultType: 设置默认的映射关系,用于属性名和表中字段名一致的情况 resultMap: 设置自定义的映射关系,用于一对多或多对一或字段名和属性名不一致的情况
2、当查询的数据为多条时,不能使用实体类作为返回值,只能使用集合,否则会抛出异常 TooManyResultsException;但是若查询的数据只有一条,可以使用实体类或集合作为返回值
MyBatis获取参数值的两种方式: ${}和 #{}
- ${} 本质字符串拼接,#{} 本质占位符赋值
- ${} 使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串或日期类型的字段进行赋值时候,可以自动添加单引号
若mapper接口中的方法参数为单个的字面量类型
此时可以使用 ${}
和 #{}
以任意的名称获取参数的值,注意${}
需要手动添加单引号
若mapper接口中的方法参数为多个时
此时Mybatis会自动将这些参数放在一个map集合中,以arg0,arg1…为键,以参数为值;以param1,param2…为键,以参数为值;因此只需要通过${}
和#{}
访问map集合的键就可以获取相对应的值,注意${}
需要手动添加单引号
若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中
只需要通过${}
和#{}
访问map集合的键就可以获取相对应的值,注意${}
需要手动加单引号
若mapper接口中的方法参数为实体类对象时
此时可以使用${}
和#{}
通过访问实体类对象中的属性名获取属性值,注意${}
需要手动加单引号
可以通过@Param注解标识mapper接口中的方法参数
此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;以 param1,param2…为键,以参数为值;只需要通过${}
和#{}
访问map集合的键就可以获取相对应的值, 注意${}
需要手动加单引号
<!--User getUserById(@Param("id") Integer id);--> <select id="getUserById" resultType="User"> select * from t_user where id = #{id} </select>
/** * 根据id查询用户信息 * * @param id * @return */ List<User> getUserById(@Param("id") Integer id);
<!--List<User> getAllUser();--> <select id="getAllUser" resultType="User"> select * from t_user; </select>
/** * 查询所有数据 * * @return */ List<User> getAllUser();
<!--Integer getCount();--> <select id="getCount" resultType="Integer"> select count(*) from t_user; </select>
/** * 查询用户信息的总记录数 * @return */ Integer getCount();
<!--Map<String, Object> getUserByIdToMap(@Param("id") Integer id);--> <select id="getUserByIdToMap" resultType="Map"> select * from t_user where id = #{id} </select>
/** * 根据id查询用户信息为一个map集合 * @param id * @return */ Map<String, Object> getUserByIdToMap(@Param("id") Integer id);
方式一:
<!--Map<String, Object> getAllUserToMap();--> <select id="getAllUserToMap" resultType="map"> select * from t_user </select>
/** * 查询所有用户信息为map集合 * @return * 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此时可以将这些map放在一个 list集合中获取 */ List<Map<String, Object>> getAllUserToMap();
方式二:
<!--Map<String,Object> getAllUserToMap();--> <select id="getAllUserToMap" resultType="map"> select * from t_user </select>
/** * 查询所有用户信息为map集合 * @return */ @MapKey("id") Map<String,Object> getAllUserToMap();
/** * MyBatis的各种查询功能 * 1、若查询出的数据只有一条 * a> 可以通过实体类对象接收 * b> 可以通过list集合接收 * c> 可以通过map集合接收 * <p> * 2、若查询出的数据有多条 * a> 可以通过实体类类型的list集合接收 * b> 可以通过map类型的list集合接收 * c> 可以在mapper接口的方法上添加@MapKey注解,此时就可以将每条数据转换的map集合为值,以某个字段的值为键,放在同一个map集合里 * <p> * 注意: 多条数据一定不能通过实体类对象接受,此时会抛异常TooManyResultsException * <p> * MyBatis中设置了默认的类型别名 * Java.lang.Integer --> int,integer * int-->_int,_integer * Map--> * String-->string */
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存池中直接获取,不会从数据库重新访问
使一级缓存失效的四种情况:
1)不同的SqlSession对应不同的一级缓存
2)同一个SqlSession但是查询条件不同
3)同一个SqlSession两次查询期间执行乐任何一次增删改操作
4)同一个SqlSession两次查询期间手动清空了缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同敢的查询语句,结果就会从缓存中获取
二级缓存开启的条件:
a>在核心配置文件中,配置全局配置属性cacheEnabled=“true”,默认为true,不需要配置
b>在映射文件中设置标签
c>二级缓存必须在SqlSession关闭或提交之后有效
使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
在mapper配置文件中添加的cache标签可以设置一些属性:
eviction属性: 缓存回收策略
flushinterval属性: 刷新间隔,单位毫秒
默认情况下不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
readOnly属性: 只读,true/false
true:只读缓存; 会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。者提供了很重要的性能优势。
false: 读写缓存; 会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
<!-- 依赖MyBatis核心包 --> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <!-- 控制Maven在构建过程中相关配置 --> <build> <!-- 构建过程中用到的插件 --> <plugins> <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.0</version> <!-- 插件的依赖 --> <dependencies> <!-- 逆向工程的核心依赖 --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.2</version> </dependency> <!-- 数据库连接池 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.2</version> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.8</version> </dependency> </dependencies> </plugin> </plugins> </build>
文件名必须是:generatorConfig.xml
<?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> <!-- targetRuntime: 执行生成的逆向工程的版本 MyBatis3Simple: 生成基本的CRUD(清新简洁版) MyBatis3: 生成带条件的CRUD(奢华尊享版) --> <context id="DB2Tables" targetRuntime="MyBatis3"> <!-- 数据库的连接信息 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root"> </jdbcConnection> <!-- javaBean的生成策略--> <javaModelGenerator targetPackage="com.learning.mybatis.pojo" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <!-- SQL映射文件的生成策略 --> <sqlMapGenerator targetPackage="com.learning.mybatis.mapper" targetProject=".\src\main\resources"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator> <!-- Mapper接口的生成策略 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.learning.mybatis.mapper" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!-- 逆向分析的表 --> <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName --> <!-- domainObjectName属性指定生成出来的实体类的类名 --> <table tableName="t_emp" domainObjectName="Emp"/> <table tableName="t_dept" domainObjectName="Dept"/> </context> </generatorConfiguration>
@Test public void testMBG() { try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory build = sqlSessionFactoryBuilder.build(is); SqlSession sqlSession = build.openSession(true); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); //查询所有数据 // List<Emp> list = mapper.selectByExample(null); // list.forEach(emp -> System.out.println(emp)); //根据条件查询 // EmpExample example = new EmpExample(); // example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThan(20); // example.or().andDidIsNotNull(); // List<Emp> list = mapper.selectByExample(example); // list.forEach(emp -> System.out.println(emp)); mapper.updateByPrimaryKeySelective(new Emp(9, "a1", 22, null, "456@qq.com", 3)); } catch (IOException e) { e.printStackTrace(); } }
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency>
在mybatis-config.xml文件中配置插件
<plugins> <!--设置分页插件--> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
a> 在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能
b> 在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据
c> 分页相关数据
常量名 | |
---|---|
pageNum | 当前页的页码 |
pageSize | 每页显示的条数 |
size | 当前页显示的真实条数 |
total | 总记录数 |
pages | 总页数 |
prePage | 上一页的页码 |
nextPage | 下一页的页码 |
isFirstPage | 是否为第一页 |
ifLastPage | 是否为最后一页 |
hasPreviousPage | 是否存在上一页 |
hasNextPage | 是否存在下一页 |
navigatePages | 导航分页的页码数 |
navigatepageNums | 导航分页的页码,[1,2,3,4,5] |