MyBatis学习笔记(一)
来源:互联网 发布:大数据自动阅卷系统 编辑:程序博客网 时间:2024/03/29 14:01
1 、对原生态jdbc程序中问题总结
jdbc编程步骤:
1、 加载数据库驱动
2、 创建并获取数据库链接
3、 创建jdbc statement对象
4、 设置sql语句
5、 设置sql语句中的参数(使用preparedStatement)
6、 通过statement执行sql并获取结果
7、 对sql执行结果进行解析处理
8、 释放资源(resultSet、preparedstatement、connection)
public static void main(String[] args) { // 数据库连接 Connection connection = null; // 预编译的Statement,使用预编译的Statement提高数据库性能 PreparedStatement preparedStatement = null; // 结果集 ResultSet resultSet = null; try { // 加载数据库驱动 Class.forName("com.mysql.jdbc.Driver"); // 通过驱动管理类获取数据库链接 connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?charactorEncoding=utf-8", "root", "root"); // 定义sql语句?表示占位符 String sql = "select * from user where username=?"; // 获取预编译处理statement preparedStatement = connection.prepareStatement(sql); // 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值 preparedStatement.setString(1, "王五"); // 向数据库发出sql执行查询,查询出结果集 resultSet = preparedStatement.executeQuery(); // 遍历查询结果集 while (resultSet.next()) { System.out.println(resultSet.getString("id") + " " + resultSet.getString("username")); } } catch (Exception e) { e.printStackTrace(); } finally { // 释放资源 if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
jdbc问题总结:
1.数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响 数据库性能。
设想:使用数据库连接池管理数据库连接。
2、将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。
设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。
3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。
设想:将sql语句及占位符号和参数全部配置在xml中。
4、从resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,,不利于系统维护。
设想:将查询的结果集,自动映射成java对象。
2、mybatis框架
MyBatis 本是apache的一个开源项目iBatis
2010年这个项目由apache software foundation 迁移到了google code
再后来托管到github下(https://github.com/mybatis/mybatis-3/releases)
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
3、入门程序示例
3.1 需求
根据用户id(主键)查询用户信息
根据用户名称模糊查询用户信息
添加用户
删除 用户
更新用户
3.2 环境
mybatis运行环境(jar包):
从https://github.com/mybatis/mybatis-3/releases下载,3.2.7版本
lib下:mybatis依赖包
mybatis-3.2.7.jar:核心包
mybatis-3.2.7.pdf,操作指南
另需:mysql的驱动包
3.3 工程结构
3.4 log4j.properties配置
mybatis默认使用log4j作为输出日志信息。
在开发环境下日志级别要设置成DEBUG,生产环境设置成info或error
# Global logging configurationlog4j.rootLogger=DEBUG, stdout# Console output...log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
3.5 SqlMapConfig.xml
SqlMapConfig.xml是mybatis核心配置文件,配置mybatis的数据源、事务管理。
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <!-- 和spring整合后 environments配置将废除--> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理--> <transactionManager type="JDBC" /> <!-- 数据库连接池--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments></configuration>
3.6 根据用户id(主键)查询用户信息
3.6.1 创建PO类
Po类作为mybatis进行sql映射使用,po类通常与数据库表对应,User.java如下:
Public class User { private int id; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址get/set……toString……}
3.6.2 映射文件
映射文件命名:
User.xml(原始ibatis命名)
mapper代理开发映射文件名称叫XXXMapper.xml,比如:UserMapper.xml、ItemsMapper.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- namespace命名空间,用于隔离sql语句,对sql进行分类化管理 --><mapper namespace="test"> <!-- 在映射文件中配置很多sql语句 --> <!-- 通过select执行数据库查询 id:标识 映射文件中的sql 将SQL语句封装到mapperStatement对象中,所以将id称为statement的id parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。 #{}表示一个占位符号,可以有效防止sql注入,可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。 ${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。 resultType:指定输出结果单条记录的类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。 --> <!-- 通过id查询用户表的记录 --> <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User"> SELECT * FROM USER WHERE id=#{id} </select></mapper>
3.6.3 在SqlMapConfig.xml中加载映射文件
在< configuration>< /configuration>标签下添加
<!-- 加载映射文件 --> <mappers> <mapper resource="sqlmap/User.xml"/> </mappers>
3.6.4 程序编写
//根据ID查询用户信息,得到一个记录 @Test public void findUserByIdTest(){ //mybatis配置文件 String resource="SqlMapconfig.xml"; SqlSession sqlSession=null; try { //得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); //创建会话工厂,传入mybatis的配置文件信息 SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream); //通过工厂得到SqlSession sqlSession=sqlSessionFactory.openSession(); //通过SqlSession操作数据库,selectOne查询一条记录,selectList可以查询一条或多条记录。 //第一个参数:映射文件中statement的id,(namespace.statement的id) //第二个参数:传入sql语句的参数值(必须为映射文件中parameterType指定的类型) //返回结果为映射文件中resultType指定类型的对象 User user=sqlSession.selectOne("test.findUserById",1); System.out.println(user); } catch (IOException e) { e.printStackTrace(); }finally{ //释放资源 if(sqlSession!=null){ sqlSession.close(); } } }
3.7 根据用户名称模糊查询用户信息
User.xml 映射文件增加
<!-- ${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。 可能引起SQL注入,所以不建议使用--> <!-- 根据用户名模糊查询用户信息 --> <select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User"> select * from user where username like '%${value}%' </select>
// 根据用户名称模糊查询用户列表 @Test public void findUserByNameTest() { // mybatis配置文件 String resource = "SqlMapconfig.xml"; SqlSession sqlSession = null; try { // 得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); // 创建会话工厂,传入mybatis的配置文件信息 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 通过工厂得到SqlSession sqlSession = sqlSessionFactory.openSession(); // 通过SqlSession操作数据库,selectOne查询一条记录,selectList可以查询一条或多条记录。 List<User> userlist = sqlSession.selectList("test.findUserByName", "小明"); System.out.println(userlist); } catch (IOException e) { e.printStackTrace(); } finally { // 释放资源 if (sqlSession != null) { sqlSession.close(); } } }
3.8 添加用户
3.8.1 代码
User.xml 映射文件增加
<!-- 添加用户 parameterType:指定输入参数类型是pojo(Plain Ordinary Java Object)简单的Java对象 #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过ognl获取对象的属性值 user.id 为自增字段,不用写 --> <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User"> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) </insert>
//添加用户信息 @Test public void insertUserTest() { // mybatis配置文件 String resource = "SqlMapconfig.xml"; SqlSession sqlSession = null; try { // 得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); // 创建会话工厂,传入mybatis的配置文件信息 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 通过工厂得到SqlSession sqlSession = sqlSessionFactory.openSession(); //插入用户对象 User user=new User(); user.setUsername("王小军"); user.setBirthday(new Date()); user.setSex("1"); user.setAddress("洛阳"); // 通过SqlSession操作数据库 sqlSession.insert("test.insertUser", user); //提交事务 sqlSession.commit(); } catch (IOException e) { e.printStackTrace(); } finally { // 释放资源 if (sqlSession != null) { sqlSession.close(); } } }
3.8.2 自增主键返回
通过修改sql映射文件,可以将mysql自增主键返回:
添加selectKey实现将主键返回
keyProperty:返回的主键存储在pojo中的哪个属性
order:selectKey的执行顺序,是相对与insert语句来说,由于mysql的自增原理执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after
resultType:返回的主键是什么类型
LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User"> <!--将插入数据的主键返回 --> <selectKey keyProperty="id" order="AFTER" resultType="java.long.Integer"> select LAST_INSERT_ID() </selectKey> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) </insert>
3.8.3 非自增主键返回 (使用uuid())
使用mysql的uuid()函数生成主键,需要修改表中id字段类型为string,长度设置成35位。
执行思路:
先通过uuid()查询到主键,将主键输入 到sql语句中。
执行uuid()语句顺序相对于insert语句之前执行。
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User"> <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String"> select uuid() </selectKey> insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address}) </insert>
通过oracle的序列生成主键:
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User"> <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String"> SELECT 序列名.nextval() </selectKey> insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address}) </insert>
3.9 删除用户
<!-- 根据id删除用户--> <delete id="deleteUser" parameterType="java.lang.Integer"> delete from user where id=#{id} </delete>
// 根据id删除用户信息 @Test public void deleteUserTest() { // mybatis配置文件 String resource = "SqlMapconfig.xml"; SqlSession sqlSession = null; try { // 得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); // 创建会话工厂,传入mybatis的配置文件信息 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 通过工厂得到SqlSession sqlSession = sqlSessionFactory.openSession(); // 通过SqlSession操作数据库 sqlSession.delete("test.deleteUser", 28); // 提交事务 sqlSession.commit(); } catch (IOException e) { e.printStackTrace(); } finally { // 释放资源 if (sqlSession != null) { sqlSession.close(); } } }
3.10 更新用户
<!-- 更新用户,User中id不能为空--> <delete id="updateUser" parameterType="cn.itcast.mybatis.po.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </delete>
//更新用户信息 @Test public void updateUserTest() { // mybatis配置文件 String resource = "SqlMapconfig.xml"; SqlSession sqlSession = null; try { // 得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); // 创建会话工厂,传入mybatis的配置文件信息 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 通过工厂得到SqlSession sqlSession = sqlSessionFactory.openSession(); //更新用户对象 User user=new User(); user.setId(27); user.setUsername("王大军"); user.setBirthday(new Date()); user.setSex("2"); user.setAddress("洛阳"); // 通过SqlSession操作数据库 sqlSession.insert("test.updateUser", user); //提交事务 sqlSession.commit(); } catch (IOException e) { e.printStackTrace(); } finally { // 释放资源 if (sqlSession != null) { sqlSession.close(); } } }
3.11 mybatis和Hibernate区别
mybatis:不完全是一个ORM(Object Relational Mapping,对象关系映射)框架,需要程序员自己编写Sql语句,不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。
可严格控制sql执行性能,灵活度高,灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。
Hibernate:对象/关系映射能力强,数据库无关性好。学习门槛高,对sql语句进行优化、修改比较困难的,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。
适用与关系模型要求高的软件(例如需求固定的定制化软件),比如:后台管理系统,erp、orm、oa。
4、mybatis开发dao的方法
4.1 需求
将下边的功能实现Dao:
根据用户id查询一个用户信息
根据用户名称模糊查询用户信息列表
添加用户信息
4.2 SqlSession的使用范围
SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。
通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。
4.2.1 SqlSessionFactoryBuilder
SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
4.2.2 SqlSessionFactory
SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。
4.2.3 SqlSession
SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作,默认使用DefaultSqlSession实现类。
执行过程如下:
1、 加载数据源等配置信息
Environment environment = configuration.getEnvironment();
2、 创建数据库链接
3、 创建事务对象
4、 创建Executor,SqlSession所有操作都是通过Executor完成
5、 SqlSession的实现类即DefaultSqlSession,此对象中对操作数据库实质上用的是Executor
结论:
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。如下:
SqlSession session = sqlSessionFactory.openSession(); try { // do work } finally { session.close(); }
4.3 原始Dao开发方式
原始Dao开发方法需要程序员编写Dao接口和Dao实现类。
4.3.1 映射文件
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- namespace命名空间,用于隔离sql语句,对sql进行分类化管理 --><mapper namespace="test"> <!-- 在映射文件中配置很多sql语句 --> <!-- 通过id查询用户表的记录 --> <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User"> SELECT * FROM USER WHERE id=#{value} </select> <select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User"> select * from user where username like '%${value}%' </select> <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User"> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> select LAST_INSERT_ID() </selectKey> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) </insert> <!-- 根据id删除用户--> <delete id="deleteUser" parameterType="java.lang.Integer"> delete from user where id=#{id} </delete> <!-- 更新用户,User中id不能为空--> <delete id="updateUser" parameterType="cn.itcast.mybatis.po.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </delete></mapper>
4.3.2 Dao接口
public interface UserDao { //根据id查询用户信息 public User findUserById(int id) throws Exception; //添加用户信息 public void insertUser(User user) throws Exception; //删除用户信息 public void deleteUser(int id) throws Exception;}
4.3.3 Dao实现
public class UserDaoImpl implements UserDao{ //需要向dao实现类注入SqlSessionFactory //这里通过构造方法注入 private SqlSessionFactory sqlSessionFactory; public UserDaoImpl(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory=sqlSessionFactory; } @Override public User findUserById(int id) throws Exception { SqlSession sqlSession=sqlSessionFactory.openSession(); User user=null; try{ user=sqlSession.selectOne("test.findUserById",id); }finally{ sqlSession.close();//释放资源 } return user; } @Override public void insertUser(User user) throws Exception { SqlSession sqlSession=sqlSessionFactory.openSession(); sqlSession.insert("test.insertUser",user);//执行插入操作 sqlSession.commit();//提交事务 sqlSession.close();//释放资源 } @Override public void deleteUser(int id) throws Exception { SqlSession sqlSession=sqlSessionFactory.openSession(); sqlSession.delete("test.deleteUser",id);//执行插入操作 sqlSession.commit();//提交事务 sqlSession.close();//释放资源 }}
4.3.4 测试
public class UserDaoImplTest { private SqlSessionFactory sqlSessionFactory; @Before public void setUp() throws Exception { //mybatis配置文件 String resource="SqlMapConfig.xml"; //得到配置文件流 InputStream inputStream=Resources.getResourceAsStream(resource); //创建回话工厂,传入mybatis的配置文件信息 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testFindUserById() throws Exception { //创建UserDao的对象 UserDao userDao=new UserDaoImpl(sqlSessionFactory); //调用UserDao的方法 User user=userDao.findUserById(1); System.out.println(user); }}
原始Dao开发中存在以下问题:
Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护。
调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型< Object>,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。
4.4 Mapper动态代理方式
4.4.1 实现原理
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
1、 Mapper.xml(本程序用UserMapper.xml)文件中的namespace与mapper接口的类路径相同。
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User"> SELECT * FROM USER WHERE id=#{value} </select>
package cn.itcast.mybatis.mapper;public interface UserMapper { //根据id查询用户信息 public User findUserById(int id) throws Exception; }
4.4.2 加载UserMapper.xml文件
修改SqlMapConfig.xml文件:
<!-- 加载映射文件 --> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers>
4.4.3 测试
public class UserMapperTest { private SqlSessionFactory sqlSessionFactory; @Before public void setUp() throws Exception { //mybatis配置文件 String resource="SqlMapConfig.xml"; //得到配置文件流 InputStream inputStream=Resources.getResourceAsStream(resource); //创建回话工厂,传入mybatis的配置文件信息 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testFindUserById() throws Exception { //获取session SqlSession sqlsession=sqlSessionFactory.openSession(); //获取mapper接口的代理对象 UserMapper userMapper=sqlsession.getMapper(UserMapper.class); //调用代理对象方法 User user=userMapper.findUserById(1); System.out.println(user); sqlsession.close(); }}
4.4.4 总结
selectOne和selectList
动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。namespace
mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。
注意:持久层方法的参数可以使用pojo、map等,service方法中建议不要使用包装类型(不利于业务层的可扩展)
5、SqlMapConfig.xml
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)settings(全局配置参数)typeAliases(类型别名)typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)environments(环境集合属性对象) environment(环境子属性对象) transactionManager(事务管理) dataSource(数据源)mappers(映射器)
5.1 properties(属性)
在classpath下定义db.properties文件
jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/mybatisjdbc.username=rootjdbc.password=root
SqlMapConfig.xml引用如下:
<!--加载属性文件 --> <properties resource="db.properties"></properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <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>
注意: MyBatis 将按照下面的顺序来加载属性:
在 properties 元素体内定义的属性首先被读取。
然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
最后读取parameterType传递的属性,它会覆盖已读取的同名属性。
因此,通过parameterType传递的属性具有最高优先级,resource或 url 加载的属性次之,最低优先级的是 properties 元素体内定义的属性。
建议:在properties文件中定义属性名要有一定的特殊性,如:XXX.XXX.XX,以防止被parameterType传递的同名属性无意覆盖。
5.2 settings全局参数配置
mybatis全局配置参数,全局参数将会影响mybatis的运行行为。
5.3 ctypeAliases(别名)重点
在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。
如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
5.3.1 mybatis默认支持别名
别名 映射的类型_byte byte _long long _short short _int int _integer int _double double _float float _boolean boolean string String byte Byte long Long short Short int Integer integer Integer double Double float Float boolean Boolean date Date decimal BigDecimal bigdecimal BigDecimal
5.3.2 自定义别名
在SqlMapConfig.xml中配置:
<typeAliases> <!-- 单个别名定义 --> <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) --> <package name="cn.itcast.mybatis.po"/> <package name="其它包"/></typeAliases>
5.4 typeHandlers(类型处理器)
每当MyBatis 设置参数到PreparedStatement 或者从ResultSet 结果集中取得值时,就会使用typeHandler 来处理数据库类型与java 类型之间转换。
<select id="findUserById" parameterType="int" resultType="user"> select * from user where id = #{id}</select>
下表描述了默认的typeHandlers:
对于用户自定义的类型,创建一个自定义的类型处理器。参考:http://blog.csdn.net/huey2672/article/details/38151607
5.5 mappers(映射器)
使用相对于类路径的资源如:<mapper resource="sqlmap/User.xml" />
使用完全限定路径如:<mapper url="file:///D:\workspace_spingmvc\mybatis_01\config\sqlmap\User.xml" />
使用mapper接口类路径如:<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
注册指定包下的所有mapper接口如:<package name="cn.itcast.mybatis.mapper"/>注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
6、输入映射
6.1 #{}与${}
#{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?。
使用占位符#{}可以有效防止sql注入
在使用时不需要关心参数值的类型,mybatis会自动进行java类型和jdbc类型的转换。
#{}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}和#{}不同,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换
${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
使用${}不能防止sql注入,但是有时用${}会非常方便
6.2 传递pojo对象
Mybatis使用ognl表达式解析对象字段的值,如下例子:
<!—传递pojo对象综合查询用户信息 --> <select id="findUserByUser" parameterType="user" resultType="user"> select * from user where id=#{id} and username like '%${username}%' </select>
6.3 传递pojo包装对象
开发中通过pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
6.3.1 定义包装类型pojo
在包装类型的pojo中将复杂的查询条件包装进去。
public class UserQueryVo {//在这里包装所需要的查询条件 //用户查询条件 private UserCustom userCustom; //还可以包装其他的查询条件,订单,商品等 public UserCustom getUserCustom() { return userCustom; } public void setUserCustom(UserCustom userCustom) { this.userCustom = userCustom; } //其他条件的getter、setter}
6.3.2 mapper.xml
在UserMapper.xml中定义用户信息综合查询
<!--用户信息综合查询 --> <select id="findUserList" parameterType="cn.itcast.mybatis.po.UserQueryVo" resultType="cn.itcast.mybatis.po.UserCustom"> select * from user where user.sex=#{userCustom.sex} and user.username like '%${userCustom.username}%' </select>
6.3.3 mapper.java
UserMapper.java 接口类中
//用户信息的综合查询 public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;
6.3.4 测试代码
UserMapperTest.java
// 用户信息的综合查询 @Test public void testFindUserList() throws Exception { // 获取session SqlSession sqlsession = sqlSessionFactory.openSession(); // 获取mapper接口的代理对象 UserMapper userMapper = sqlsession.getMapper(UserMapper.class); //创建包装对象,设置查询条件 UserQueryVo userQueryVo=new UserQueryVo(); UserCustom userCustom=new UserCustom(); userCustom.setSex("1"); userCustom.setUsername("张"); userQueryVo.setUserCustom(userCustom); List<UserCustom> list=userMapper.findUserList(userQueryVo); System.out.println(list); sqlsession.close(); }
6.4 传递hashmap
Sql映射文件定义如下:
<!-- 传递hashmap综合查询用户信息 --> <select id="findUserByHashmap" parameterType="hashmap" resultType="user"> select * from user where id=#{id} and username like '%${username}%' </select>
id和username是hashmap的key
异常测试:
传递的map中的key和sql中解析的key不一致。
测试结果没有报错,只是通过key获取值为空。
7、输出映射
7.1 resultType
可输出简单类型、pojo对象、pojo列表、hashmap
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象,其他属性为相应类型的默认值。
输出pojo对象和输出pojo列表在sql中定义的resultType是一样的。
返回单个pojo对象要保证sql查询出来的结果集为单条,内部使用session.selectOne方法调用,mapper接口使用pojo对象作为方法返回值。
返回pojo列表表示查询出来的结果集可能为多条,内部使用session.selectList方法,mapper接口使用List对象作为方法返回值。
输出pojo对象可以改用hashmap输出类型,将输出的字段名称作为map的key,value为字段值。
7.2 resultMap
resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
7.2.1 定义reusltMap和statement
UserMapper.xml
<!--定义resultMap --> <!-- type:resultMap最终映射的java对象类型,可以使用别名 id:对此resultMap的标识 --> <resultMap type="User" id="userResultMap"> <!-- id表示查询结果集中唯一标识 column:查询出来的列名 property:type指定的pojo类型中对应的属性名 --> <id column="id_" property="id"/> <!-- result:查询结果中普通列名 --> <result column="username_" property="username"/> </resultMap> <select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap"> select id id_,username username_ from user where id=#{value} </select>
UserMapper.java接口
//根据id查询用户信息,使用resultMap输出 public User findUserByIdResultMap(int id) throws Exception;
8、动态SQL(重点)
8.1 if 和 where
<!-- 用户信息综合查询总数--> <select id="findUserCount" parameterType="cn.itcast.mybatis.po.UserQueryVo" resultType="int"> select count(*) from user <!-- where可以自动去掉条件中的第一个and --> <where> <if test="userCustom!=null"> <if test="userCustom.sex!=null and userCustom.sex!=''"> and user.sex=#{userCustom.sex} </if> <if test="userCustom.username!=null and userCustom.username!=''"> and user.username like '%${userCustom.username}%' </if> </if> </where> </select>
8.2 foreach
8.2.1 通过pojo传递list
在pojo中定义list属性ids存储多个用户id,并添加getter/setter方法
public class UserQueryVo {//在这里包装所需要的查询条件 //用户查询条件 private UserCustom userCustom; //传递多个用户id private List<Integer> ids;、//getter/setter...}
UserMapper.xml
<select id="findUsersByIds" parameterType="cn.itcast.mybatis.po.UserQueryVo" resultType="cn.itcast.mybatis.po.UserCustom"> SELECT * FROM USER <where> <if test="ids!=null and ids.size>0"> <foreach collection="ids" item="id" open=" and id in(" close=")" separator="," > #{id} </foreach> </if> </where> </select>
Mapper接口
public List<UserCustom> findUsersByIds(UserQueryVo userQueryVo) throws Exception;
测试代码
@Test public void findUsersByIds() throws Exception { // 获取session SqlSession sqlsession = sqlSessionFactory.openSession(); // 获取mapper接口的代理对象 UserMapper userMapper = sqlsession.getMapper(UserMapper.class); List<Integer> ids=new ArrayList<Integer>(); ids.add(1); ids.add(10); UserQueryVo userQueryVo=new UserQueryVo(); userQueryVo.setIds(ids); List<UserCustom> list=userMapper.findUsersByIds(userQueryVo); System.out.println(list); sqlsession.close(); }
8.2.2 传递单个List
传递List类型在编写mapper.xml没有区别,唯一不同的是只有一个List参数时它的参数名为list。
UserMapper.xml
<select id="findUserByList" parameterType="java.util.List" resultType="cn.itcast.mybatis.po.UserCustom"> select * from user <where> <!-- 传递List,List中是pojo --> <if test="list!=null"> <foreach collection="list" item="item" open="and id in(" close=")" separator=","> #{item.id} </foreach> </if> </where> </select>
Mapper接口
public List<UserCustom> findUserByList(List userlist) throws Exception;
测试代码
@Test public void findUserByList()throws Exception{ //获取session SqlSession session = sqlSessionFactory.openSession(); //获限mapper接口实例 UserMapper userMapper = session.getMapper(UserMapper.class); //构造查询条件List List<User> userlist = new ArrayList<User>(); User user = new User(); user.setId(1); userlist.add(user); user = new User(); user.setId(2); userlist.add(user); //传递userlist列表查询用户列表 List<UserCustom>list = userMapper.findUserByList(userlist); //关闭session session.close(); }
8.2.3 传递单个数组(数组中是pojo)
<!-- 传递数组综合查询用户信息 --> <select id="selectUserByArray" parameterType="Object[]" resultType="user"> select * from user <where> <!-- 传递数组 --> <if test="array!=null"> <foreach collection="array" index="index" item="item" open="and id in("separator=","close=")"> #{item.id} </foreach> </if> </where> </select>
sql只接收一个数组参数,这时sql解析参数的名称mybatis固定为array,如果数组是通过一个pojo传递到sql则参数的名称为pojo中的属性名。
index:为数组的下标。
item:为数组每个元素的名称,名称随意定义
open:循环开始
close:循环结束
separator:中间分隔输出
8.2.4 传递单个数组(数组中是字符串类型)
<!-- 传递数组综合查询用户信息 --> <select id="selectUserByArray" parameterType="Object[]" resultType="user"> select * from user <where> <!-- 传递数组 --> <if test="array!=null"> <foreach collection="array" index="index" item="item" open="and id in(" separator="," close=")"> #{item} </foreach> </if> </where> </select>
如果数组中是简单类型则写为#{item},不用再通过ognl获取对象属性值了。
8.3 sql片段
Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的,如下:
<!-- 传递pojo综合查询用户信息 --> <select id="findUserList" parameterType="user" resultType="user"> select * from user <where> <if test="id!=null and id!=''"> and id=#{id} </if> <if test="username!=null and username!=''"> and username like '%${username}%' </if> </where> </select>
将where条件抽取出来:
<sql id="query_user_where"> <if test="id!=null and id!=''"> and id=#{id} </if> <if test="username!=null and username!=''"> and username like '%${username}%' </if></sql>
使用include引用:
<select id="findUserList" parameterType="user" resultType="user"> select * from user <where> <include refid="query_user_where"/> </where></select>
注意:如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace,如下:
- Mybatis学习笔记--(一)Mybatis基础
- MyBatis学习笔记(一)--初识MyBatis
- mybatis学习笔记(一)
- Mybatis学习笔记(一)
- Mybatis学习笔记(一)
- MyBatis学习笔记(一)
- MyBatis学习笔记(一)
- MyBatis学习笔记(一)
- MyBatis学习笔记(一)
- MyBatis学习笔记(一)
- MyBatis学习笔记(一)
- mybatis学习笔记(一)
- MyBatis学习笔记(一)
- MyBatis 学习笔记一
- MyBatis学习笔记一
- mybatis学习笔记一
- Mybatis学习笔记一
- # MyBatis学习笔记(一)快速入门
- 为ViewPager设置CirclePageIndicator(小圆点)
- RadioButton+ViewPager+FragmentPagerAdapter快速搭建页面结构
- 常见的对话框Dialog
- 分解质因数
- LoadMoreListView+SwipeRefreshLayout(分页下拉)基本结构
- MyBatis学习笔记(一)
- HorizontalScrollView+RadioGroup+ViewPager+FragmentPagerAdapter基本结构
- 快速上传头像到服务端工具类FaceUtil
- 手势滑动销毁Activity
- zxing二维码扫描功能
- 排序算法总结
- android5.x之Palette调色板
- 模拟退火算法
- 关于struts2 result param name的详解