使用原始dao层进行开发
UserMapper层接口
public interface UserMapper { /** * 通过id查询用户 * @param id * @return */ User queryUserById(Integer id); }
UserMapper层的实现类
public class UserMapperImpl implements UserMapper{ private SqlSessionFactory sqlSessionFactory; //使用构造方法进行注入sqlSessionFactory public UserMapperImpl(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } /** * 通过id查询用户 * * @param id * @return */ @Override public User queryUserById(Integer id) { SqlSession sqlSession = sqlSessionFactory.openSession(); User user = (User)sqlSession.selectOne("test.queryUserById", 2); return user; } }
测试类
*/ public class DaoTest { @Test() public void daoTest() throws IOException { InputStream inputStream = Resources.getResourceAsStream("SqlMapperConfig.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); UserMapperImpl userMapper = new UserMapperImpl(sqlSessionFactory); User user = userMapper.queryUserById(2); System.out.println(user); } }
最后的结果为:
使用动态代理进行开发.
定义一个Mapper接口,这个接口其实和我们UserDao接口是一样的,从Mybatis框架中拿到一个代理对象(代理的是这个Mapper接口),通过代理对象调用接口当中的方法完成业务.
传统dao开发方式中的实现类其实起了一个连接,承上启下的作用,连接了接口和xml映射文件,效果就是调用接口中方法时能够找到xml映射文件.
Mapper动态代理开发遵从的规范:
1.sql映射文件的namespace必须和mapper接口的全限定类名保持一致
2.mapper接口的接口方法名必须和xml中的sql语句id保持一致.
3.mapper接口的接口方法形参类型必须和sql语句的输入参数类型保持一致
4.mapper接口的接口方法返回类型必须和sql语句的resultType保持一致
UserMapper接口
public interface UserMapper { User queryUserById(Integer id); }
UserMapper.xml配置文件
<!-- namespace属性值=接口全限定名--> <mapper namespace="com.itheima.mapper.UserMapper"> <!-- id属性值=方法名--> <select id="queryUserById" parameterType="Integer" resultType="com.itheima.pojo.User"> select * from user where id=#{id} </select> </mapper>
测试类
@Test public void userMapper() throws IOException { InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserById(2); System.out.println(user); }
总结:关于使用动态代理,就是将不用通过
UserMapperImpl userMapper = new UserMapperImpl(sqlSessionFactory);这个方法获取到UserMapper对象,然后再操作里面的方法,
而是通过
UserMapper mapper = sqlSession.getMapper(UserMapper.class);这个方法获取到动态代理对象,间接的操作这个类里面的方法.
然后达到目的.
全局properties的配置
重新创建一个db.properties文件
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.user=root jdbc.password=root
将这个文件引入到SqlMapperConfig.xml中
<properties resource="db.properties"></properties>
然后修改SqlMapperConfig.xml文件
<dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.user}"/> <property name="password" value="${jdbc.password}"/> </dataSource>
<typeAliases> <!-- 为pojo对象定义别名--> <typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias> </typeAliases>
<!-- 使用别名即可--> <select id="queryUserById" parameterType="int" resultType="User"> select * from user where id=#{id} </select>
扫描所有pojo包下的类。注意:不可以出现相同的类名
<typeAliases> <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>--> <!-- 自动扫描pojo包下的全部类--> <package name="com.itheima.pojo" ></package> </typeAliases>
全局配置文件mappers
mappers注册sql映射文件的
-
resource属性加载sql映射文件,万能型选手(crud、原始dao、mapper动态代理)
-
针对Mapper动态代理进行一个增强(增强两种用法)
-
mapper class 单个注册
-
package 批量扫描注册
-
以上两种方式有规范要求
<mappers> <mapper resource="sqlmapper/UserMapper.xml" /> <mapper resource="mapper/UserMapper.xml" /> <mapper class="com.itheima.mapper.UserMapper"></mapper> <package name="com.itheima.mapper"></package> </mappers>
MyBatis输入参数类型
parameterType(输入参数类型)
1.传递简单类型
2.传递Pojo对象
3.传递Pojo包装对象
QueryVO类
public class QueryVo { private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
UserMapper接口
public interface UserMapper { User queryUserById(Integer id); List<User> queryUserByQueryVo(QueryVo queryVo); }
UserMapper接口类 传入的参数为queryVO,然后查询时候,需要使用User类中的username通过#{user.username}获取
<select id="queryUserByQueryVo" resultType="user" parameterType="queryvo"> select * from user where username like #{user.username} </select>
Test测试类
@Test public void userMapperQueryVo(){ // 获取到工厂建造者对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 通过本类加载器获取到一个流对象,这个流对象用来读取SqlMapperConfig.xml文件 InputStream inputStream = SqlMapperTest.class.getClassLoader().getResourceAsStream("sqlMapperConfig.xml"); // 创建工厂对象 sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); // 获取到映射对象,getMapper("实现类",接口.class) UserMapper mapper = sqlSession.getMapper(UserMapper.class); QueryVo queryVo = new QueryVo(); User user = new User(); //将要查询的东西,封装在user类中 user.setUsername("%王%"); queryVo.setUser(user); List<User> list = mapper.queryUserByQueryVo(queryVo); for(User u :list){ System.out.println(u); } sqlSession.close(); }
MyBatis的手动映射
当数据库中的列名和domain类中的属性名,不能对应上的时候,就会出现封装数据失败,mybatis无法将数据表中数据准确的封装到domain对象中,因此必须使用手动映射方式,
domain类
private Integer id; private Integer userId; private String number; private Date createtime; private String note;
Mapper接口
public interface OrdersMapper { List<Orders> queryOrders(); }
xml配置文件
<mapper namespace="com.itheima.mapper.OrdersMapper"> <select id="queryOrders" resultMap="order"> select * from orders </select> <!-- id属性值=resultMap属性值--> <resultMap id="order" type="com.itheima.pojo.Orders"> <!-- 配置pojo对象红的属性名和数据表列名的对应关系 --> <id property="id" column="id"></id> <result property="userId" column="user_id"></result> //property 为domian中的属性名,column为数据库中的列名 <result property="number" column="number"></result> <result property="createtime" column="createtime"></result> <result property="note" column="note"></result> </resultMap> </mapper>
Test测试类
@Test public void ordersMapper(){ SqlSession sqlSession = sqlSessionFactory.openSession(); OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class); List<Orders> list = ordersMapper.queryOrders(); for(Orders orders : list){ System.out.println(orders); } sqlSession.close(); }
MyBatis连接池
在Mybatis的配置文件中,这个位置配置了数据源,,也就是使用了连接池.
那么连接池是在什么时候建立的,什么时候从连接池中获取连接的.
连接池初始化的时机:
在SqlSessionFactoryBuilder构建SqlSessionFactory的时候初始化的连接池,初始化之后,放入Configuration对象中,分析框架的源代码:
org.apache.ibatis.builder.xml.XMLConfigBuilder类的方法environmentsElement()
什么时候从连接池中获取连接
在getMapper的时候是不会从数据库连接池中获取数据库连接的,在具体操作数据库调用mapper接口方法的时候才会从连接池拿连接.
UNPOOLED:不适用数据库连接池(一般情况下不使用)
JNDI:(前提是你的Mybatis环境必须是Web应用)
什么是JNDI?
JNDI:java naming directory interface(java命名目录接口,它是一种服务发布技术),数据源可以以服务的形式发布出去,那么哪个应用想用,就类似于客户端调用远程服务一样去调用即可.
为什么必须是wen应用?
往往只有tomcat./weblogic服务中间件才支持JNDI技术.
如果Mybatis当中用,怎么用?
第一步:在数据库驱动程序(jar包)放到tomcat安装目录下的lib文件夹下.
第二步:在Tomcat的conf/context.xml文件中进行jndi数据源服务配置
<Resource name="jndi/mybatis" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/mybatis? characterEncoding=utf8" username="root" password="root" maxActive="20" maxIdle="10" maxWait="10000"> </Resource>
name:在JNDI中叫做目录名,等同于服务名,此处的jndi/mybatis是自定义的,往往以/连接前后字符串即可。auth和type是固定的,其他都是数据库连接池的具体配置信息。
第三步 :在自己web项目的web.xml中引用Jndi数据源服务。
<resource-ref>
<res-ref-name>jndi/mybatis</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
第四步:在自己web项目的Mybatis配置文件中使用
<property name="data_source"
value="java:comp/env/jndi/mybatis"/>
配置data_source属性,指向你的数据源引用,java:comp/env/jndi/mybatis中红色部分是固定的,绿色部分是你自己定义的目录名(服务名)。
MyBatis事务控制
通过sqlSession.openSession这种方法操作数据库时候,mybatis默认把事务自动提交给关闭了,注意:数据量非常小可以自动提交,数据量大就应该手动提交。自动提交在openSession
方法中传入参数true: SqlSession sqlSession = sqlSessionFactory.openSession(true)
动态SQL标签
where和if标签
需求:根据用户的性别和用户名多条件查询用户信息
<select id="queryUserByWhere" resultType="user" parameterType="user"> select * from user where sex=#{sex} and username like #{username} </select>
@Test public void queryUserByWhere(){ SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setSex("2"); user.setUsername("%王%"); List<User> list = mapper.queryUserByWhere(user); if(list!=null && list.size()>0){ for(User user1 : list){ System.out.println(user1); } } }
以上查询是可以查询到相关的数据的,假定不传递sex的值,那么就会出现什么也差不到的结果?
通过日志可以看出,MyBatis在执行SQL语句的时候,参数sex的值是null,因此没有查询到结果。在以往的做法是判断参数是否为空,并进行字符串的拼接。在MyBatis框架中,提供了where标签和if标签来实现动态SQL语句。
where标签:处理SQL语句,自动添加where关键字,并去掉紧跟他后面的一个and或者or
if标签:test属性,判断表达式真假
<select id="queryUserByWhere" resultType="user" parameterType="user"> select * from user <where> <if test="sex!=''and sex!=null"> and sex=#{sex} </if> <if test="username!=''and username!=null"> and username like #{username} </if> </where> </select>
SQL标签
将SQL语句抽取,其他SQL语句中引入
<!-- SQL片段抽取 使用include标签引入 --> <sql id="commonsSql"> id,username,sex,birthday,address </sql>
引入外部xml配置文件中的共享SQL片段时,使用namespace属性值+“.”+sql标签的id属性值。
foreach标签传入集合
删除多条数据的SQL语句,delete from user where id in(1,2,3)
String sql = "delete from user where id in(" for(int i=0; i<list.size();i++) { if(i != list.size()-1) sql += list.get(i) + "," else sql += list.get(i)+")" }
foreach标签遍历拼接SQL语句
collection属性:遍历传入的集合,当参数是集合时collection属性值固定为list
open属性:遍历拼接前
close属性:遍历拼接后
separator属性:拼接的符号
item属性:遍历到的元素
<select id="queryUserByIdsList" parameterType="list" resultType="user"> select * from user <foreach collection="list" open="where id in(" close=")" separator="," item="item"> #{item} </foreach> </select>
@Test public void queryUserByIdsList(){ SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<Integer> idsList = new ArrayList<Integer>(); idsList.add(1); idsList.add(2); idsList.add(3); List<User> list = mapper.queryUserByIdsList(idsList); if(list!=null && list.size()>0){ for (User user : list){ System.out.println(user); } } sqlSession.close(); }
foreach标签传入数组
foreach标签遍历拼接SQL语句
collection属性:遍历传入的集合,当参数是数组时collection属性值固定为array
open属性:遍历拼接前
close属性:遍历拼接后
separator属性:拼接的符号
item属性:遍历到的元素
<select id="queryUserByIdsArray" parameterType="int[]" resultType="user"> select * from user <foreach collection="array" open="where id in(" close=")" separator="," item="item"> #{item} </foreach>
@Test public void queryUserByIdsArray(){ SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int[] idsArray= {1,2,3}; List<User> list = mapper.queryUserByIdsArray(idsArray); if(list!=null && list.size()>0){ for (User user : list){ System.out.println(user); } } sqlSession.close(); }
foreach标签传入pojo对象
foreach标签遍历拼接SQL语句
collection属性:遍历传入的pojo对象中的集合,collection属性配置pojo中成员变量名
open属性:遍历拼接前
close属性:遍历拼接后
separator属性:拼接的符号
item属性:遍历到的元素
public class QueryVo { private List<Integer> idsList; public List<Integer> getIdsList() { return idsList; } public void setIdsList(List<Integer> idsList) { this.idsList = idsList; } }
<select id="queryUserByQueryVo" parameterType="queryVo" resultType="user"> select * from user <foreach collection="idsList" open="where id in(" close=")" separator="," item="item"> #{item} </foreach> </select>
@Test public void queryUserByQueryVo(){ SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); QueryVo queryVo = new QueryVo(); List<Integer> idsList = new ArrayList<Integer>(); idsList.add(1); idsList.add(2); idsList.add(3); queryVo.setIdsList(idsList); List<User> list = mapper.queryUserByQueryVo(queryVo); if(list!=null && list.size()>0){ for (User user : list){ System.out.println(user); } } sqlSession.close(); }