一.Mabatis架构
二.操作步骤
-
1.导包(mybatis包+依赖包+数据库驱动包)
-
2.配置文件:sqlMapConfig.xml+User.xml…
-
3.获取SQLSession
//加载核心配置文件 String resource = "sqlMapConfig.xml"; InputStream in = Resources.getResourceAsStream(resource); //创建SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); //创建SqlSession SqlSession sqlSession = sqlSessionFactory.openSession();
-
4.元数据配置
<mapper namespace="com.itheima.mybatis.mapper.UserMapper"> <!-- parameterType:入参类型 resultType:结果参数类型 --> <!-- 通过ID查询一个用户 --> <select id="findUserById" parameterType="Integer" resultType="User"> select * from user where id = #{v} </select> <!-- //根据用户名称模糊查询用户列表 #{} select * from user where id = ? 占位符 ? == '五' ${} select * from user where username like '%五%' 字符串拼接 --> <selectid="findUserByUsername"parameterType="String" resultType="com.itheima.mybatis.pojo.User"> select * from user where username like "%"#{haha}"%" </select> <!-- 添加用户 --> <insert id="insertUser" parameterType="com.itheima.mybatis.pojo.User"> <!--插入后获取User的id--> <selectKey keyProperty="id" resultType="Integer" order="AFTER"> select LAST_INSERT_ID() </selectKey> insert into user (username,birthday,address,sex) values (#{username},#{birthday},#{address},#{sex}) </insert> <!-- 更新 --> <update id="updateUserById" parameterType="com.itheima.mybatis.pojo.User"> update user set username = #{username}, sex = #{sex}, birthday = #{birthday}, address = #{address} where id = #{id} </update> <!-- 删除 --> <delete id="deleteUserById" parameterType="Integer"> delete from user where id = #{vvvvv} </delete> </mapper>
-
5.根据语句的id来执行sql
// 执行Sql语句 User user = sqlSession.selectOne("test.findUserById", 10); System.out.println(user);
// 执行Sql语句 User user = new User(); user.setUsername("小何"); user.setBirthday(new Date()); user.setAddress("sadfsafsafs"); user.setSex("男"); int i = sqlSession.insert("test.insertUser", user); sqlSession.commit(); // id已经封装到User中了 System.out.println(user.getId());
三.Mybatis与Hibernate区别(面试题)
- 1.Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。
- 2.Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
- 3.Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行 .
四.Mapper动态代理开发(只需写接口不需要实现类)
-
遵循四个原则
1.接口中的函数名要和Mapper.xml中的id相同
2.返回值类型要和Mapper.xml中的resultType相同
3.方法的参数要与Mapper.xml中的parameterType相同
4.Mapper.xml的namespace的值为接口的完整路径*
-
操作过程
1.接口
public interface UserMapper { /** * 根据id查询 * * @param id * @return */ User queryUserById(int id); /** * 根据用户名查询用户 * * @param username * @return */ List<User> queryUserByUsername(String username); /** * 保存用户 * * @param user */ void saveUser(User user); }
2.Mapper.xml
<?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"> <!-- 1.namespace:命名空间,用于隔离sql --> <!-- 2.namespace必须和Mapper接口类路径一致 --> <mapper namespace="cn.itcast.mybatis.mapper.UserMapper"> <!-- 根据用户id查询用户 --> <!-- 2. id必须和Mapper接口方法名一致 --> <!-- 3. parameterType必须和接口方法参数类型一致 --> <!-- 4. resultType必须和接口方法返回值类型一致 --> <select id="queryUserById" parameterType="int" resultType="cn.itcast.mybatis.pojo.User"> select * from user where id = #{id} </select> <!-- 根据用户名查询用户 --> <select id="queryUserByUsername" parameterType="string" resultType="cn.itcast.mybatis.pojo.User"> select * from user where username like '%${value}%' </select> <!-- 保存用户 --> <insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User"> <selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="int"> select last_insert_id() </selectKey> insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address}); </insert> </mapper>
3.测试
public class UserMapperTest { private SqlSessionFactory sqlSessionFactory; @Before public void init() throws Exception { // 创建SqlSessionFactoryBuilder SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 加载SqlMapConfig.xml配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 创建SqlsessionFactory this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); } @Test public void testQueryUserById() { // 获取sqlSession,和spring整合后由spring管理 SqlSession sqlSession = this.sqlSessionFactory.openSession(); // ******从sqlSession中获取Mapper接口的代理对象***** UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 执行查询方法 User user = userMapper.queryUserById(1); System.out.println(user); // 和spring整合后由spring管理 sqlSession.close(); }
五.sqlMapConfig.xml详解
-
properties:用于读取properties文件
<!-- 是用resource属性加载外部配置文件 --> <properties resource="db.properties"> <!-- 在properties内部用property定义属性 --> <!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 --> <property name="jdbc.username" value="root123" /> <property name="jdbc.password" value="root123" /> </properties>
-
typeAliases:别名
<typeAliases> <!-- 单个别名定义 --> <typeAlias alias="user" type="cn.itcast.mybatis.pojo.User" /> <!-- 批量别名定义,扫描整个包及子包下的类,别名为类名(大小写不敏感) --> <package name="cn.itcast.mybatis.pojo" /> <package name="其它包" /> </typeAliases>
-
mapper:映射
1.使用相对路径的资源
<mappers> <mapper resource="com/tz/pojo/User.xml"/> </mappers>
2.使用Mapper接口类路径
<mappers> <mapper class="cn.itcast.mybatis.mapper.UserMapper"/> </mappers>
注意:此种方法要求**Mapper接口名称(Mapper.java)和Mapper映射文件(Mapper.xml)**名称相同,且放在同一个目录中。
3.注册指定包下的所有mapper接口
<mappers> <package name="cn.itcast.mybatis.mapper"/> </mappers>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
六.输入映射和输出映射
-
parameterType(输入)
1.传递简单类型
2.传递pojo
3.传递pojo包装对象
-
resultType(输出)
1.输出简单类型
2.输出pojo对象
3.输出pojo列表
-
resultMap(输出)
用于pojo与sql字段不一致时使用
<!--type是返回值类型--> <resultMap type="order" id="orderResultMap"> <!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id --> <!-- property:主键在pojo中的属性名 --> <!-- column:主键在数据库中的列名 --> <id property="id" column="id" /> <!-- 定义普通属性 --> <result property="userId" column="user_id" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> </resultMap> <!-- 查询所有的订单数据 --> <select id="queryOrderAll" resultMap="orderResultMap"> SELECT id, user_id,number,createtime, note FROM `order` </select>
七.动态SQL(通过mybatis提供的各种标签方法实现动态拼接sql)
-
if标签:用于判断是否添加条件
<select id="queryUserByWhere" parameterType="user" resultType="user"> SELECT id, username, birthday, sex, address FROM `user` WHERE 1=1 <if test="sex != null and sex != ''"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </select>
-
where标签:上面的sql还有where 1=1 这样的语句,很麻烦可以使用where标签进行改造(前and)
<select id="queryUserByWhere" parameterType="user" resultType="user"> SELECT id, username, birthday, sex, address FROM `user` <!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字 --> <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select>
-
sql片段
<!-- 根据条件查询用户 --> <select id="queryUserByWhere" parameterType="user" resultType="user"> <!-- SELECT id, username, birthday, sex, address FROM `user` --> <!-- 使用include标签加载sql片段;refid是sql片段id --> SELECT <include refid="userFields" /> FROM `user` <!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 --> <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select> <!-- 声明sql片段 --> <sql id="userFields"> id, username, birthday, sex, address </sql>
-
foreach标签:向sql传递数组或List,mybatis使用foreach
<!-- 根据ids查询用户 --> <select id="queryUserByIds" parameterType="queryVo" resultType="user"> SELECT * FROM `user` <where> <!-- foreach标签,进行遍历 --> <!-- collection:遍历的集合,这里是QueryVo的ids属性,数组就是array,list就是list --> <!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 --> <!-- open:在前面添加的sql片段 --> <!-- close:在结尾处添加的sql片段 --> <!-- separator:指定遍历的元素之间使用的分隔符 --> <foreach collection="ids" item="item" open="id IN (" close=")" separator=","> #{item} </foreach> </where> </select>
注意:使用vo对象是*时collection写的是vo中数组或list的属性名,而数组是array,list为list
八.关联查询
-
一对一查询
<resultMap type="order" id="orderUserResultMap"> <id property="id" column="id" /> <result property="userId" column="user_id" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> <!-- association :配置一对一属性 --> <!-- property:order里面的User属性名 --> <!-- javaType:属性类型 --> <association property="user" javaType="user"> <!-- id:声明主键,表示user_id是关联查询对象的唯一标识--> <id property="id" column="user_id" /> <result property="username" column="username" /> <result property="address" column="address" /> </association> </resultMap> <!-- 一对一关联,查询订单,订单内部包含用户属性 --> <select id="queryOrderUserResultMap" resultMap="orderUserResultMap"> SELECT o.id,o.user_id,o.number,o.createtime,o.note,u.username,u.address FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id </select>
-
一对多映射
<resultMap type="user" id="userOrderResultMap"> <id property="id" column="id" /> <result property="username" column="username" /> <result property="birthday" column="birthday" /> <result property="sex" column="sex" /> <result property="address" column="address" /> <!-- 配置一对多的关系 --> <collection property="orders" javaType="list" ofType="order"> <!-- 配置主键,是关联Order的唯一标识 --> <id property="id" column="oid" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> </collection> </resultMap> <!-- 一对多关联,查询订单同时查询该用户下的订单 --> <select id="queryUserOrder" resultMap="userOrderResultMap"> SELECT u.id,u.username,u.birthday,u.sex,u.address,o.id oid,o.number,o.createtime,o.note FROM `user` u LEFT JOIN `order` o ON u.id = o.user_id </select>
九.Mybatis整合Spring
-
整合思路
1.SqlSessionFactory对象应该放到spring容器中作为单例存在。
2.传统dao的开发方式中,应该从spring容器中获得sqlsession对象。
3.Mapper代理形式中,应该从spring容器中直接获得mapper的代理对象。
4.数据库的连接以及数据库连接池事务管理都交给spring容器来完成。
-
配置SqlSessionFactoryBean
<!-- 加载配置文件 --> <context:property-placeholder location="classpath:db.properties" /> <!-- 数据库连接池 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="maxActive" value="10" /> <property name="maxIdle" value="5" /> </bean> <!-- 配置SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 配置mybatis核心配置文件 --> <property name="configLocation" value="classpath:sqlMapConfig.xml" /> <!-- 配置数据源 --> <property name="dataSource" ref="dataSource" /> </bean> </beans>
原始dao开发,继承SqlSessionDaoSupport(类似HibernateDaoSupport),只需注入sqlSessionFactory;
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao { @Override public User queryUserById(int id) { // 获取SqlSession SqlSession sqlSession = super.getSqlSession(); // 使用SqlSession执行操作 User user = sqlSession.selectOne("queryUserById", id); // 不要关闭sqlSession return user; } }
Mapper代理开发dao:
1.创建接口,使用代理子类,mybatis中使用MapperFactoryBean来创建代理对象
<!-- Mapper代理的方式开发方式一,配置Mapper代理对象 --> <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <!-- 配置Mapper接口 --> <property name="mapperInterface" value="cn.itcast.mybatis.mapper.UserMapper" /> <!-- 配置sqlSessionFactory --> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
由spring创建Mapper工厂,再由工厂创建代理类
2.扫描包形式不用配置factory
<!-- Mapper代理的方式开发方式二,扫描包方式配置代理 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 配置Mapper接口,包下所有的接口 --> <property name="basePackage" value="cn.itcast.mybatis.mapper" /> </bean>
每个mapper代理对象的id就是类名,首字母小写
十.Mybatis逆向工程
<?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">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg" password="yycg"> </jdbcConnection> -->
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL
和 NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="cn.itcast.ssm.po"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="cn.itcast.ssm.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="cn.itcast.ssm.mapper" targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定数据库表 -->
<table schema="" tableName="user"></table>
<table schema="" tableName="order"></table>
</context>
</generatorConfiguration>