MyBatis入门--第一天

来源:互联网 发布:光纤分路器 什么网络 编辑:程序博客网 时间:2024/05/17 08:55

mybatis 入门

 

下载:https://github.com/mybatis/mybatis-3/releases

 

对原生态jdbc程序中问题总结

1 数据库连接,使用时创建,不使用立即释放,对数据库进行频繁连接开启或关闭,造成数据库资源浪费,影响数据库性能。

解决方案:使用数据库连接池管理数据库连接

2 sql语句硬编码到java代码中,如果sql语句更改,需要重新编译java代码,不利于系统维护(硬编码:代码写死了) 

 

解决方案:将sql语句配置在xm配置文件中,即使sql变化,不需要对java代码进行重新编译

3 preparedstatement中设置参数,对占位符位置和设置参数,硬编码在java代码中,不利于系统维护

解决:将sql语句及占位符位置和设置参数全部配置在xml

4 resultset中遍历结果集数据时,存在硬编码,将获取表的字段进行了硬编码,不利于系统维护

解决:将查询的结果集自动映射成java对象

 

 

mybatis框架:

mybatis是一个持久层的框架,是apache下的顶级项目

mybatis SQL语句独立在Java代码之外,为程序的修改和纠错提供了更大的灵活性,可以直接修改SQL语句,而无需重新编译Java程序。

mybatis可以将preparedstatement中输入参数自动进行输入映射,将查询结果集灵活映射出java对象(输出映射

mybatis

 

hibernate:重量级框架   封装了很多东东 ,不好带代码进行优化  struts

mybatis:    轻量级     封装jdbc ---映射

 

ibatis   -----  mybaits

awt          swing

 

 

 

 

 

 

 

mybatis中首先要在配置文件中配置一些东西,然后根据这些配置去创建一个会话工厂,再根据会话工厂创建会话,会话发出操作数据库的sql语句,然后通过执行器操作数据,再使用mappedStatement对数据进行封装

 

 

 

 

需求:

mybatis驱动包+sql驱动包

 

 

步骤:  

1 src下新建log4j.properties文件 或在项目下新建source folder文件夹,把配置文件放在里面也行(项目下的第一级source folder文件夹就相当于src),

source folderfolder区别:source folder文件夹下放要用到的java配置文件,如xmljava会编译执行它,而普通folder文件夹放一些程序员自己管理的文件,如图片等,java不会编译执行它

配置:

注意:开发环境下设置DEBUG,生产环境下设置infoerror(用于调试)

 

#Global logging configuration

 log4j.rootLogger=DEBUG,stdout

# Console output

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%5p [%t] -%m%n

 

2 创建SqlMapConfig.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>

<!-- 和spring整合后 environments配置将废除-->

<environments default="development">

<environment id="development">

<!-- 使用jdbc事务管理-->

<transactionManager type="JDBC" />

<!-- 数据库连接池-->

<dataSource type="POOLED">

<property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>

<property name="url" value="jdbc:sqlserver://127.0.0.1:1433;databasename=userDB"/>

<property name="username" value="sa"/>

<property name="password" value="123"/>

</dataSource>

</environment>

</environments>

</configuration>

 

如果是mysql

 

<dataSource type="POOLED">

<property name="driver" value="com.mysql.jdbc.Driver" />

<property name="url" value="jdbc:mysql://localhost:3306/xxx" />

<property name="username" value="root" />

<property name="password" value="123456" />

</dataSource>

 

 

 

3  创建映射文件   (例子:根据id查询)

 1) 原始的ibatis的命名方式  :user.xml     

 2mapper代理开发映射方式:xxxmapper.xmlusermapper.xml

这里使用user.xml

在映射文件中配置sql语句

<?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">

<!-- namespace命名空间,作用就是对sql进行分类化管理(sql隔离)

注意:使用mapper代理方法开发,namespace有特殊的作用

 -->

<mapper namespace="test">

<!-- 在映射文件中配置sql语句 -->

<!-- 用<select>执行数据库查询  id:sql语句唯一标识,称为statement的id

sql语句封装到mappedStatement对象中,所以将id称为statement的id

#{}表示一个占位符:会自动在外包裹引号:如果是order by #{xx}相当于 order by

如果输入参数是简单类型(String,int,double..)#{}中的参数名可以任意

#{id}:其中的id表示输入参数

parameterType:指定输入参数类型,这里指定int

resultType:返回结果集类型User_tb是写的一个和表对应的类,这里写完整的包名类名

-->

<select id="findUserById" parameterType="int" resultType="com.beans.User_tb">

select * from user_tb where id=#{id}

</select>

</mapper>

 

3.5 同时封装类如:

public class User_tb {

//属性名和数据库表的字段对应

private int id;

private String name;

private String sex;

private Date birthday;

private String address;

 

4 SqlMapConfig.xmlconfiguration下最末尾加载映射文件

<mappers>

<mapper resource="user_tb.xml" />

</mappers>

 

最终的SqlMapConfig.xml:

<?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>

<!-- 和spring整合后 environments配置将废除-->

<environments default="development">

<environment id="development">

<!-- 使用jdbc事务管理-->

<transactionManager type="JDBC" />

<!-- 数据库连接池-->

<dataSource type="POOLED">

<property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>

<property name="url" value="jdbc:sqlserver://127.0.0.1:1433;databasename=userDB"/>

<property name="username" value="sa"/>

<property name="password" value="123"/>

</dataSource>

</environment>

</environments>

<mappers>

<mapper resource="user.xml" />

</mappers>

</configuration>

 

 

5获取一行数据: selectOne()

//mybatis配置文件

String resource="SqlMapConfig.xml";

//得到配置文件流

InputStream is= Resources.getResourceAsStream(resource);

//创建会话工厂,传入mybatis的配置文件信息

SqlSessionFactory ssf= new SqlSessionFactoryBuilder().build(is);

//通过工厂得到SqlSession

SqlSession sqlsession=ssf.openSession();

//通过SqlSession操作数据库

//第一个参数:映射文件中statement的id,等于   namespace+"."+statement的id

//第二个参数:指定和映射文件中所匹配的paramenterType类型参数

//sqlsession.selectOne结果是与映射文件中所匹配的resultType类型对象

User_tb user= sqlsession.selectOne("test.findUserById", 1);

System.out.println(user);

//释放会话资源

sqlsession.close();

 

 

例子:根据用户名模糊查询   selectList()

步骤:使用User.xml

<!-- 根据用户名模糊查询用户信息,可能返回多条

${}:表示拼接sql,( 将传入的数据直接显示在sql语句中(传的是什么就是什么,不会在外面自动添加引号))如果传递的是order by ${xx} order by

但使用${}拼接sql,引起sql注入攻击,但没办法,如果是#{}能够防止sql注入攻击

${value}:接受输入参数内容,如果传入类型是简单类型,${}中只能使用value

一般${}用于like模糊匹配,尽量用#

-->

<select id="findUserByName" parameterType="java.lang.String" resultType="com.beans.User_tb">

select * from user_tb where name like '%${value}%'

</select>

 

主函数:

// 根据用户名模糊查询用户信息

public static  void findUserByName()throws IOException{

String resource="SqlMapConfig.xml";

InputStream is= Resources.getResourceAsStream(resource);

SqlSessionFactory ssf= new SqlSessionFactoryBuilder().build(is);

SqlSession sqlsession=ssf.openSession();

List<User_tb>  list=sqlsession.selectList("test.findUserByName","张");

System.out.println(list.size());

}

添加用户:

使用User.xml

<!-- 添加用户

parameterType:指定输入参数类型是对象

#{}中指定对象的属性名,接受到对象的属性,mybatis通过OGNL获取对象的属性值-->

<insert id="addUser" parameterType="com.beans.User_tb">

insert into user_tb  values (#{name},#{sex},#{birthday},#{address})

</insert>

主函数:

//添加用户

public static  void addUser()throws IOException{

String resource="SqlMapConfig.xml";

InputStream is= Resources.getResourceAsStream(resource);

SqlSessionFactory ssf= new SqlSessionFactoryBuilder().build(is);

SqlSession sqlsession=ssf.openSession();

//创建对象

User_tb u=new User_tb("校花","男", new Date(),"河南");

sqlsession.insert("test.addUser",u );

//提交事务

sqlsession.commit();   //增删改需要提交事务

//关闭会话

sqlsession.close();

}

 

自增主键返回:执行insert提交之自动生成一个自增主键,该主键用于外键表的操作

通过函数获取到刚刚插入记录的自增主键    select @@IDENTITY

mysql的语法为:select last_insert_id()

 

使用User.xml

<insert id="addUser" parameterType="com.beans.User_tb">

<!-- 将插入数据的主键返回,返回到user对象中

select @@IDENTITY:得到刚insert进去记录的主键值,只适用于自增主键

keyProperty:将查询到主键值设置到 parameterType 指定的对象的哪个属性

order: select @@IDENTITY 执行顺序,相对于insert语句来说它的执行顺序

SelectKey需要注意order属性,像MySQL一类支持自动增长类型的数据库中,order需要设置为after才会取到正确的值。像Oracle这样取序列的情况,需要设置为before,否则会报错。

resultType:指定 select @@IDENTITY的结果类型

-->

<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">

select @@IDENTITY

</selectKey>

insert into user_tb  values (#{name},#{sex},#{birthday},#{address})

</insert>

主函数:在提交(sqlsession.commit();)后面可以打印测试u.getId()

 

删除用户:

<!-- 删除用户 -->

<delete id="deleteUser" parameterType="java.lang.Integer">

delete from user_tb where id=#{id}

</delete>

 

更新用户

<!-- 更新用户 -->

<update id="updateUser" parameterType="com.beans.User_tb">

update user_tb set name=#{name},sex=#{sex},birthday=#{birthday},address=#{address} where  id=#{id}

</update>

 

总结:#{} ${}

#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

 

${}表示拼接sql串,通过${}可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value

能用#{}就不要用${}

 

mybatis排序时使用order by动态参数时需要住哟,使用$而不是#

 

1.1.1 selectOneselectList

 

selectOne表示查询出一条记录进行映射。如果使用selectOne可以实现使用selectList也可以实现(list中只有一个对象)。

 

selectList表示查询出一个列表(多条记录)进行映射。如果使用selectList查询多条记录,不能使用selectOne

 

如果使用selectOne报错:

org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4

 

1.1 mybatishibernate本质区别和应用场景

 

hibernate:是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序写sqlsql语句自动生成了。

sql语句进行优化、修改比较困难的。

应用场景:

适用与需求变化不多的中小型项目,比如:后台管理系统,erpormoa。。

(因为hibernate是一个重量级框架)

 

mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全 的ORM框架,虽然程序员自己写sqlmybatis也可以实现映射(输入映射、输出映射)。

应用场景:

适用与需求变化较多的项目,比如:互联网项目。

企业进行技术选型,以低成本 高回报作为技术选型的原则,根据项目组的技术力量进行选择。

 

1.1.1 SqlSession

SqlSession是一个面向用户(程序员)的接口。

SqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)selectList(返回单个或多个对象)、。

 

SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性???

 

SqlSession最佳应用场合在方法体内,定义成局部变量使用。

 

 

原始dao开发方法(程序员需要写dao接口和dao实现类)

1.1.2 dao接口

步骤:

1 dao接口

public interface UserDao {

//根据id查询用户

public User_tb findUserById(int id)throws Exception;

//添加

public void addUser(User_tb user)throws Exception;

//删除

public void  delUser(int id)throws Exception;

}

2 写该接口的实现类


public class UserDaoImplimplements UserDao {

//需要向dao实现类注入SqlSessionFactory

//这里通过构造方法注入

 private  SqlSessionFactoryssf;

public UserDaoImpl(SqlSessionFactory ssf) {

this.ssf = ssf;

}

 

@Override

public User_tb findUserById(int id)throws Exception {

SqlSession sqlSession=ssf.openSession();

User_tb user= sqlSession.selectOne("test.findUserById", id);

sqlSession.close();

return user;

}

 

@Override

public void addUser(User_tb user)throws Exception {

SqlSession sqlsession=ssf.openSession();

//创建对象

sqlsession.insert("test.addUser",user);

//提交事务

sqlsession.commit();

//关闭会话

sqlsession.close();

}

 

@Override

public void delUser(int id)throws Exception {

SqlSession sqlsession=ssf.openSession();

sqlsession.delete("test.deleteUser", 4);

//提交事务

sqlsession.commit();

//关闭会话

sqlsession.close();

}

 

测试代码:

 

 

public class dao测试 {

public static void main(String[] args)throws Exception {

String resource="SqlMapConfig.xml";

InputStream is= Resources.getResourceAsStream(resource);

SqlSessionFactory ssf= new SqlSessionFactoryBuilder().build(is);

SqlSession sqlsession=ssf.openSession();

UserDaoImpl udi=new UserDaoImpl(ssf);

User_tb u= udi.findUserById(2);

System.out.println(u);

}

}

 

1.1.3 总结原始 dao开发问题

1dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。

 

2、调用sqlsession方法时将statementid硬编码了:即类似于”test.findUserById”这种,都写死了。

 

 

3sqlSession的方法中,要求传入的参数是Object类型的(泛型),也就是说如果我传错了参数,编译不会报错,执行的时候才会报错,不利于开发。

 

 

原创粉丝点击