洛谷 P1004 方格取數(DP)
其實Javaweb就想直接加在裡面但,感覺不全面就算了吧.....
首先為什麼使用Mybatis?
在沒有mybatis前,java連線資料庫和寫sql語句是怎麼樣的?!
public class IStudentDaoImpl implements IStudentDao { private Connection conn=null; private PreparedStatement pst=null; private ResultSet rs=null; /** * 通過ID執行單個查詢 * @param i * @return*/ @Override public List<Student> selectOne(long i) { List<Student> list = new ArrayList<>(); // 查詢表中所有資料 String sql="Select * FROM student where id=?"; try { conn = JDBCUtil.getConnection(); // 預編譯語句 pst = conn.prepareStatement(sql); pst.setLong(1,i); // 執行DDL操作 rs = pst.executeQuery(); list = JDBCUtil.loopSet(rs); } catch (SQLException throwables) { throwables.printStackTrace(); }finally { JDBCUtil.close(pst,conn,rs); } return list; }
}
資料庫連線
public classJDBCUtil { private static DataSource ds; private static Properties p=new Properties(); static { try( //java6的新特性,try()中自動關閉 InputStream in = Thread.currentThread().getContextClassLoader() .getResourceAsStream("db.properties") ) { p.load(in); /*Class.forName(p.getProperty("driverClassName"));*/ ds= DruidDataSourceFactory.createDataSource(p); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { /* try { return DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"),p.getProperty("password")); } catch (SQLException throwables) { throwables.printStackTrace(); } return null;*/ return ds.getConnection(); }
我們需要在這裡面寫sql,連線資料庫,關閉資料庫連線,提交事務,
那麼假設我們有很多的表要寫,那這個工作量有多大?且sql和java程式碼混雜在一起,以後維護起來方便嗎?!
他可以解決我們什麼問題?
幫我們把sql語句抽取出來,讓程式碼便於維護,分離
連線資料庫,再也不用寫在java程式碼裡一個配置檔案搞定連線煩惱
環境準備
mybatis-xxx.jar
mysql-connector-java-xxx-bin.jar
2.mybatis:mybatis-config.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>
<environments default="dev_mysql"> <environment id="dev_mysql"> <!--Mybatis 內建事務管理器--> <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="admin"/> </dataSource> </environment> </environments> <mappers> <!--mapper檔案的路徑--> <mapper resource="xxx.xml"/> </mappers> </configuration>
mybatis中訪問的SQL語句都是在mapper配置檔案中的
<?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 : 名稱空間(通俗說法: 給當前對映檔案的唯一標識:起一個唯一的名字) --> <mapper namespace="cn.ss.mybatis.pojo.UserMapper"> <!-- 新增操作 id: 當前功能的唯一標識,和介面方法同名 parameterType : 引數的型別 useGeneratedKeys:是否返回資料庫生成的主鍵 true是/false否 keyProperty : 資料庫主鍵對應java的pojo物件的屬性 keyColumn : 資料表的主鍵列明 --> <insert id="insertUserInfo" parameterType="User" useGeneratedKeys="true" keyProperty="id" keyColumn="id" ></mapper>
其實獲取連線物件還是需要用到連線池物件(為什麼使用連線池物件的原因是為了減少對資料庫資源浪費)
舉個栗子:
在沒有使用資料庫連線池之前,我們每次呼叫資料庫都要開一個數據庫連線
而資料庫的連線是有限的,當一個專案為了一些操作不斷的開啟資料庫連線
這樣最終會導致資料庫崩潰.
連線池就是起到,當你使用完資料庫連線後,呼叫關閉並不是放回資料庫,而是放入資料庫連線池等待下次呼叫
而mybatis的資料庫連線物件時SqlSessionFactory 中獲取SqlSession
try (SqlSession session = sqlSessionFactory.openSession()) { BlogMapper mapper = session.getMapper(BlogMapper.class ); Blog blog = mapper.selectBlog(101); }
注意:這裡的(BlogMapper.class)指的是介面檔案的位元組碼檔案,要匹配到介面修改xml檔案的空間命名!!!!!
另外註解和通過SqlSession例項來直接執行SQL的我就不寫了(有想了解的百度吧)
ResultMap 的設計思想是,簡單的語句不需要明確的結果對映,而複雜一點的語句只需要描述它們的關係就行了。
type 類的完全限定名, 或者一個類型別名 (內建的別名可以參考上面的表格).
association – 一個複雜型別的關聯;許多結果將包裝成這種型別
巢狀結果對映 – 關聯可以指定為一個 resultMap 元素,或者引用一個
<resultMap id="baseResultMap" type="Department"> <id column="id" property="id"/> <result column="name" property="name"/> <!--關聯屬性是集合型別 使用collection來配置 select 傳送而外的sql column 而外sql引數之前sql那些列的值 property 查詢結果封裝部門物件什麼屬性 --> <collection select="cn.wolfcode.mapper.EmployeeMapper.queryById" column="id" property="employees"/> </resultMap>
<select id="insertUserInfo" resultType="User" > select * from user where password=#{param1} and username=#{param2} </select>
通過預設命名獲取引數
而為了解決這種,不清晰的方式mybatis,提供了註解,讓你在傳遞多個引數前提前給個命名
void selectOne(@Param("username")String username,@Param("password")String password)
優勢:以前拼接的時候需要注意的空格、列表最後的逗號等,現在都可以不用手動處理了
-
if
可選的查詢薪水功能
<select id="QueryByList" restult="employee"> SELECT id,name,salary FROM employee where <if test="minSalary !=null"> salary >=#{minSalary} </if> <if test="maxSalary !=null"> and salary <=#{minSalary} </if> </select>
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
-
trim ,where, set
<select id="QueryByList" restult="employee"> SELECT id,name,salary FROM employee <where> <if test="minSalary !=null"> salary >=#{minSalary} </if> <if test="maxSalary !=null"> and salary <=#{minSalary} </if> </where> </select>
<!-- colletion 遍歷陣列或集合的key,或者屬性名 open 遍歷開始拼接的字串 index 遍歷索引 item 遍歷元素 separator 每遍歷一個元素拼接的字串 close 遍歷拼接結束的字串 --> <delete id="batchDelete"> delete from employee where id IN <foreach collection="ids" open="(" item="id" separator="," close=")"> #{id} </foreach>
相同點:
都可以獲取物件(Map物件或者JAVABean物件)資訊
不同點:
使用#傳遞的引數會先轉換為,無論傳遞是什麼型別資料都會帶一個單引號;$傳遞的引數,直接把值作為SQL語句的一部分
使用#支援把簡單型別引數作為值;$不支援簡單型別為值
使用#好比使用PrepareStatement,沒有sql注入的問題,比較安全;而$則反之
但這樣是不是$就沒用了呢?!
其實不然例如ORDER BY 或GROUP BY字句獲取引數值使用$,因為這樣會直接拼接在SQL上
(#加引號導致找不到列),因此若需要獲取引數才使用#
**(使用$可以攜帶常量)